char* ExeBinaryFile::SymbolByAddr(ADDRESS dwAddr) { if (dwAddr == GetMainEntryPoint()) return const_cast<char *>("main"); // No symbol table handled at present return 0; }
// We at least need to be able to name the main function and system calls const char* PalmBinaryFile::SymbolByAddress(ADDRESS dwAddr) { if ((dwAddr & 0xFFFFF000) == 0xAAAAA000) { // This is the convention used to indicate an A-line system call unsigned offset = dwAddr & 0xFFF; if (offset < numTrapStrings) return trapNames[offset]; else return 0; } if (dwAddr == GetMainEntryPoint()) return "PilotMain"; else return 0; }
bool MachOBinaryFile::RealLoad(const char* sName) { m_pFileName = sName; FILE *fp = fopen(sName,"rb"); unsigned int imgoffs = 0; unsigned char magic[12*4]; fread(magic, sizeof(magic), 1, fp); if (magic[0] == 0xca && magic[1] == 0xfe && magic[2] == 0xba && magic[3] == 0xbe) { int nimages = BE4(4); #ifdef DEBUG_MACHO_LOADER printf("binary is universal with %d images\n", nimages); #endif for (int i = 0; i < nimages; i++) { int fbh = 8 + i * 5*4; unsigned int cputype = BE4(fbh); unsigned int cpusubtype = BE4(fbh+4); unsigned int offset = BE4(fbh+8); unsigned int size = BE4(fbh+12); unsigned int pad = BE4(fbh+16); #ifdef DEBUG_MACHO_LOADER printf("cputype: %08x\n", cputype); printf("cpusubtype: %08x\n", cpusubtype); printf("offset: %08x\n", offset); printf("size: %08x\n", size); printf("pad: %08x\n", pad); #endif if (cputype == 0x7) // i386 imgoffs = offset; } } fseek(fp, imgoffs, SEEK_SET); header = new struct mach_header; fread(header, sizeof(*header), 1, fp); if ((header->magic != MH_MAGIC) && (_BMMH(header->magic) != MH_MAGIC)) { fclose(fp); fprintf(stderr,"error loading file %s, bad Mach-O magic\n", sName); return false; } // check for swapped bytes swap_bytes = (_BMMH(header->magic) == MH_MAGIC); // Determine CPU type if (BMMH(header->cputype) == 0x07) machine = MACHINE_PENTIUM; else machine = MACHINE_PPC; sections.clear(); std::vector<struct segment_command> segments; std::vector<struct nlist> symbols; unsigned startlocal, nlocal, startdef, ndef, startundef, nundef; std::vector<struct section> stubs_sects; char *strtbl = NULL; unsigned *indirectsymtbl = NULL; ADDRESS objc_symbols = NO_ADDRESS, objc_modules = NO_ADDRESS, objc_strings = NO_ADDRESS, objc_refs = NO_ADDRESS; unsigned objc_modules_size = 0; fseek(fp, imgoffs + sizeof(*header), SEEK_SET); for (unsigned i = 0; i < BMMH(header->ncmds); i++) { struct load_command cmd; long pos = ftell(fp); fread(&cmd, 1, sizeof(struct load_command), fp); fseek(fp, pos, SEEK_SET); switch (BMMH(cmd.cmd)) { case LC_SEGMENT: { struct segment_command seg; fread(&seg, 1, sizeof(seg), fp); segments.push_back(seg); #ifdef DEBUG_MACHO_LOADER fprintf(stdout, "seg addr %x size %i fileoff %x filesize %i flags %x\n", BMMH(seg.vmaddr), BMMH(seg.vmsize), BMMH(seg.fileoff), BMMH(seg.filesize), BMMH(seg.flags)); #endif for (unsigned n = 0; n < BMMH(seg.nsects); n++) { struct section sect; fread(§, 1, sizeof(sect), fp); sections.push_back(sect); #ifdef DEBUG_MACHO_LOADER fprintf(stdout, " sectname %s segname %s addr %x size %i flags %x\n", sect.sectname, sect.segname, BMMH(sect.addr), BMMH(sect.size), BMMH(sect.flags)); #endif if ((BMMH(sect.flags) & SECTION_TYPE) == S_SYMBOL_STUBS) { stubs_sects.push_back(sect); #ifdef DEBUG_MACHO_LOADER fprintf(stdout, " symbol stubs section, start index %i, stub size %i\n", BMMH(sect.reserved1), BMMH(sect.reserved2)); #endif } if (!strcmp(sect.sectname, SECT_OBJC_SYMBOLS)) { assert(objc_symbols == NO_ADDRESS); objc_symbols = BMMH(sect.addr); } if (!strcmp(sect.sectname, SECT_OBJC_MODULES)) { assert(objc_modules == NO_ADDRESS); objc_modules = BMMH(sect.addr); objc_modules_size = BMMH(sect.size); } if (!strcmp(sect.sectname, SECT_OBJC_STRINGS)) { assert(objc_strings == NO_ADDRESS); objc_strings = BMMH(sect.addr); } if (!strcmp(sect.sectname, SECT_OBJC_REFS)) { assert(objc_refs == NO_ADDRESS); objc_refs = BMMH(sect.addr); } } } break; case LC_SYMTAB: { struct symtab_command syms; fread(&syms, 1, sizeof(syms), fp); fseek(fp, imgoffs + BMMH(syms.stroff), SEEK_SET); strtbl = new char[BMMH(syms.strsize)]; fread(strtbl, 1, BMMH(syms.strsize), fp); fseek(fp, imgoffs + BMMH(syms.symoff), SEEK_SET); for (unsigned n = 0; n < BMMH(syms.nsyms); n++) { struct nlist sym; fread(&sym, 1, sizeof(sym), fp); symbols.push_back(sym); #ifdef DEBUG_MACHO_LOADER //fprintf(stdout, "got sym %s flags %x value %x\n", strtbl + BMMH(sym.n_un.n_strx), sym.n_type, BMMH(sym.n_value)); #endif } #ifdef DEBUG_MACHO_LOADER fprintf(stdout, "symtab contains %i symbols\n", BMMH(syms.nsyms)); #endif } break; case LC_DYSYMTAB: { struct dysymtab_command syms; fread(&syms, 1, sizeof(syms), fp); #ifdef DEBUG_MACHO_LOADER fprintf(stdout, "dysymtab local %i %i defext %i %i undef %i %i\n", BMMH(syms.ilocalsym), BMMH(syms.nlocalsym), BMMH(syms.iextdefsym), BMMH(syms.nextdefsym), BMMH(syms.iundefsym), BMMH(syms.nundefsym)); #endif startlocal = BMMH(syms.ilocalsym); nlocal = BMMH(syms.nlocalsym); startdef = BMMH(syms.iextdefsym); ndef = BMMH(syms.nextdefsym); startundef = BMMH(syms.iundefsym); nundef = BMMH(syms.nundefsym); #ifdef DEBUG_MACHO_LOADER fprintf(stdout, "dysymtab has %i indirect symbols: ", BMMH(syms.nindirectsyms)); #endif indirectsymtbl = new unsigned[BMMH(syms.nindirectsyms)]; fseek(fp, imgoffs + BMMH(syms.indirectsymoff), SEEK_SET); fread(indirectsymtbl, 1, BMMH(syms.nindirectsyms)*sizeof(unsigned), fp); #ifdef DEBUG_MACHO_LOADER for (unsigned j = 0; j < BMMH(syms.nindirectsyms); j++) { fprintf(stdout, "%i ", BMMH(indirectsymtbl[j])); } fprintf(stdout, "\n"); #endif } break; default: #ifdef DEBUG_MACHO_LOADER fprintf(stderr, "not handled load command %x\n", BMMH(cmd.cmd)); #endif // yep, there's lots of em break; } fseek(fp, pos + BMMH(cmd.cmdsize), SEEK_SET); } struct segment_command *lowest = &segments[0], *highest = &segments[0]; for (unsigned i = 1; i < segments.size(); i++) { if (BMMH(segments[i].vmaddr) < BMMH(lowest->vmaddr)) lowest = &segments[i]; if (BMMH(segments[i].vmaddr) > BMMH(highest->vmaddr)) highest = &segments[i]; } loaded_addr = BMMH(lowest->vmaddr); loaded_size = BMMH(highest->vmaddr) - BMMH(lowest->vmaddr) + BMMH(highest->vmsize); base = (char *)malloc(loaded_size); if (!base) { fclose(fp); fprintf(stderr,"Cannot allocate memory for copy of image\n"); return false; } m_iNumSections = segments.size(); m_pSections = new SectionInfo[m_iNumSections]; for (unsigned i = 0; i < segments.size(); i++) { fseek(fp, imgoffs + BMMH(segments[i].fileoff), SEEK_SET); ADDRESS a = BMMH(segments[i].vmaddr); unsigned sz = BMMH(segments[i].vmsize); unsigned fsz = BMMH(segments[i].filesize); memset(base + a - loaded_addr, 0, sz); fread(base + a - loaded_addr, 1, fsz, fp); m_pSections[i].pSectionName = new char[17]; strncpy(m_pSections[i].pSectionName, segments[i].segname, 16); m_pSections[i].pSectionName[16] = 0; m_pSections[i].uNativeAddr = BMMH(segments[i].vmaddr); m_pSections[i].uHostAddr = (ADDRESS)base + BMMH(segments[i].vmaddr) - loaded_addr; m_pSections[i].uSectionSize = BMMH(segments[i].vmsize); unsigned long l = BMMH(segments[i].initprot); m_pSections[i].bBss = false; // TODO m_pSections[i].bCode = l&VM_PROT_EXECUTE?1:0; m_pSections[i].bData = l&VM_PROT_READ?1:0; m_pSections[i].bReadOnly = (l&VM_PROT_WRITE)?0:1; #ifdef DEBUG_MACHO_LOADER fprintf(stderr, "loaded segment %x %i in mem %i in file code=%i data=%i readonly=%i\n", a, sz, fsz, m_pSections[i].bCode, m_pSections[i].bData, m_pSections[i].bReadOnly); #endif } // process stubs_sects for (unsigned j = 0; j < stubs_sects.size(); j++) { for (unsigned i = 0; i < BMMH(stubs_sects[j].size) / BMMH(stubs_sects[j].reserved2); i++) { unsigned startidx = BMMH(stubs_sects[j].reserved1); unsigned symbol = BMMH(indirectsymtbl[startidx + i]); ADDRESS addr = BMMH(stubs_sects[j].addr) + i * BMMH(stubs_sects[j].reserved2); #ifdef DEBUG_MACHO_LOADER fprintf(stdout, "stub for %s at %x\n", strtbl + BMMH(symbols[symbol].n_un.n_strx), addr); #endif char *name = strtbl + BMMH(symbols[symbol].n_un.n_strx); if (*name == '_') // we want printf not _printf name++; m_SymA[addr] = name; dlprocs[addr] = name; } } // process the remaining symbols for (unsigned i = 0; i < symbols.size(); i++) { char *name = strtbl + BMMH(symbols[i].n_un.n_strx); if (BMMH(symbols[i].n_un.n_strx) != 0 && BMMH(symbols[i].n_value) != 0 && *name != 0) { #ifdef DEBUG_MACHO_LOADER fprintf(stdout, "symbol %s at %x type %x\n", name, BMMH(symbols[i].n_value), BMMH(symbols[i].n_type) & N_TYPE); #endif if (*name == '_') // we want main not _main name++; m_SymA[BMMH(symbols[i].n_value)] = name; } } // process objective-c section if (objc_modules != NO_ADDRESS) { #ifdef DEBUG_MACHO_LOADER_OBJC fprintf(stdout, "processing objective-c section\n"); #endif for (unsigned i = 0; i < objc_modules_size; ) { struct objc_module *module = (struct objc_module *)((ADDRESS)base + objc_modules - loaded_addr + i); char *name = (char *)((ADDRESS)base + BMMH(module->name) - loaded_addr); Symtab symtab = (Symtab)((ADDRESS)base + BMMH(module->symtab) - loaded_addr); #ifdef DEBUG_MACHO_LOADER_OBJC fprintf(stdout, "module %s (%i classes)\n", name, BMMHW(symtab->cls_def_cnt)); #endif ObjcModule *m = &modules[name]; m->name = name; for (unsigned j = 0; j < BMMHW(symtab->cls_def_cnt); j++) { struct objc_class *def = (struct objc_class *)((ADDRESS)base + BMMH(symtab->defs[j]) - loaded_addr); char *name = (char *)((ADDRESS)base + BMMH(def->name) - loaded_addr); #ifdef DEBUG_MACHO_LOADER_OBJC fprintf(stdout, " class %s\n", name); #endif ObjcClass *cl = &m->classes[name]; cl->name = name; struct objc_ivar_list *ivars = (struct objc_ivar_list *)((ADDRESS)base + BMMH(def->ivars) - loaded_addr); for (unsigned k = 0; k < static_cast<unsigned int>(BMMH(ivars->ivar_count)); k++) { struct objc_ivar *ivar = &ivars->ivar_list[k]; char *name = (char*)((ADDRESS)base + BMMH(ivar->ivar_name) - loaded_addr); char *types = (char*)((ADDRESS)base + BMMH(ivar->ivar_type) - loaded_addr); #ifdef DEBUG_MACHO_LOADER_OBJC fprintf(stdout, " ivar %s %s %x\n", name, types, BMMH(ivar->ivar_offset)); #endif ObjcIvar *iv = &cl->ivars[name]; iv->name = name; iv->type = types; iv->offset = BMMH(ivar->ivar_offset); } // this is weird, why is it defined as a ** in the struct but used as a * in otool? struct objc_method_list *methods = (struct objc_method_list *)((ADDRESS)base + BMMH(def->methodLists) - loaded_addr); for (unsigned k = 0; k < static_cast<unsigned int>(BMMH(methods->method_count)); k++) { struct objc_method *method = &methods->method_list[k]; char *name = (char*)((ADDRESS)base + BMMH(method->method_name) - loaded_addr); char *types = (char*)((ADDRESS)base + BMMH(method->method_types) - loaded_addr); #ifdef DEBUG_MACHO_LOADER_OBJC fprintf(stdout, " method %s %s %x\n", name, types, BMMH((void*)method->method_imp)); #endif ObjcMethod *me = &cl->methods[name]; me->name = name; me->types = types; me->addr = BMMH((void*)method->method_imp); } } i += BMMH(module->size); } } // Give the entry point a symbol // ADDRESS entry = GetMainEntryPoint(); entrypoint = GetMainEntryPoint(); fclose(fp); return true; }