/**************************** macho.cpp ******************************* * Author: Agner Fog * Date created: 2007-01-06 * Last modified: 2008-06-02 * Project: objconv * Module: macho.cpp * Description: * Module for reading Mach-O files * * Class CMACHO is used for reading, interpreting and dumping Mach-O files. * * Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses *****************************************************************************/ #include "stdafx.h" // Machine names SIntTxt MacMachineNames[] = { {MAC_CPU_TYPE_I386, "Intel 32 bit"}, {MAC_CPU_TYPE_X86_64, "Intel 64 bit"}, {MAC_CPU_TYPE_ARM, "Arm"}, {MAC_CPU_TYPE_SPARC, "Sparc"}, {MAC_CPU_TYPE_POWERPC, "Power PC 32 bit"}, {MAC_CPU_TYPE_POWERPC64, "Power PC 64 bit"} }; // CPU subtype names SIntTxt MacCPUSubtypeNames[] = { {MAC_CPU_SUBTYPE_POWERPC_ALL, "Power PC All"}, {MAC_CPU_SUBTYPE_I386_ALL, "Intel All"} }; // File type names SIntTxt MacFileTypeNames[] = { {MAC_OBJECT, "Relocatable object file"}, {MAC_EXECUTE, "demand paged executable file"}, {MAC_FVMLIB, "fixed VM shared library file"}, {MAC_CORE, "core file"}, {MAC_PRELOAD, "preloaded executable file"}, {MAC_DYLIB, "dynamicly bound shared library file"}, {MAC_DYLINKER, "dynamic link editor"}, {MAC_BUNDLE, "dynamicly bound bundle file"} }; // Command type names SIntTxt MacCommandTypeNames[] = { {MAC_LC_SEGMENT, "Segment"}, {MAC_LC_SYMTAB, "Symbol table"}, {MAC_LC_SYMSEG, "gdb symbol table info (obsolete)"}, {MAC_LC_THREAD, "thread"}, {MAC_LC_UNIXTHREAD, "unix thread"}, {MAC_LC_LOADFVMLIB, "load a specified fixed VM shared library"}, {MAC_LC_IDFVMLIB, "fixed VM shared library identification"}, {MAC_LC_IDENT, "object identification info (obsolete)"}, {MAC_LC_FVMFILE, "fixed VM file inclusion (internal use)"}, {MAC_LC_PREPAGE, "prepage command (internal use)"}, {MAC_LC_DYSYMTAB, "dynamic link-edit symbol table info"}, {MAC_LC_LOAD_DYLIB, "load a dynamicly linked shared library"}, {MAC_LC_ID_DYLIB, "dynamicly linked shared lib identification"}, {MAC_LC_LOAD_DYLINKER, "load a dynamic linker"}, {MAC_LC_ID_DYLINKER, "dynamic linker identification"}, {MAC_LC_PREBOUND_DYLIB, "modules prebound for a dynamicly linked shared library"}, {MAC_LC_ROUTINES, "image routines"}, {MAC_LC_SUB_FRAMEWORK, "sub framework"}, {MAC_LC_SUB_UMBRELLA, "sub umbrella"}, {MAC_LC_SUB_CLIENT, "sub client"}, {MAC_LC_SUB_LIBRARY, "sub library"}, {MAC_LC_TWOLEVEL_HINTS, "two-level namespace lookup hints"}, {MAC_LC_PREBIND_CKSUM, "prebind checksum"}, {MAC_LC_LOAD_WEAK_DYLIB&0xFF, "load a dynamically linked shared library, all symbols weak"}, {MAC_LC_SEGMENT_64, "64-bit segment"}, {MAC_LC_ROUTINES_64, "64-bit image routine"}, {MAC_LC_UUID, "uuid"} }; // Relocation type names, 32 bit SIntTxt Mac32RelocationTypeNames[] = { {MAC32_RELOC_VANILLA, "Generic"}, {MAC32_RELOC_PAIR, "Second entry of a pair"}, {MAC32_RELOC_SECTDIFF, "Section diff"}, {MAC32_RELOC_PB_LA_PTR, "Prebound lazy "}, {MAC32_RELOC_LOCAL_SECTDIFF, "SectDif local"} }; // Relocation type names, 64 bit SIntTxt Mac64RelocationTypeNames[] = { {MAC64_RELOC_UNSIGNED, "absolute address"}, {MAC64_RELOC_SIGNED, "signed 32-bit displ."}, {MAC64_RELOC_BRANCH, "Rel. jump 32-bit displ."}, {MAC64_RELOC_GOT_LOAD, "MOVQ load of a GOT entry"}, {MAC64_RELOC_GOT, "other GOT reference"}, {MAC64_RELOC_SUBTRACTOR, "Subtractor"}, {MAC64_RELOC_SIGNED_1, "signed 32-bit displacement with -1 addend"}, {MAC64_RELOC_SIGNED_2, "signed 32-bit displacement with -2 addend"}, {MAC64_RELOC_SIGNED_4, "signed 32-bit displacement with -4 addend"} }; // Symbol type names SIntTxt MacSymbolTypeNames[] = { {MAC_N_UNDF, "Undefined, no section"}, {MAC_N_ABS, "Absolute, no section"}, {MAC_N_SECT, "Defined"}, {MAC_N_PBUD, "Prebound undefined (defined in a dylib)"}, {MAC_N_INDR, "Indirect"} }; // Symbol reference type names SIntTxt MacSymbolReferenceTypeNames[] = { {MAC_REF_FLAG_UNDEFINED_NON_LAZY, "External non lazy"}, {MAC_REF_FLAG_UNDEFINED_LAZY, "External lazy (function call)"}, {MAC_REF_FLAG_DEFINED, "Defined public"}, {MAC_REF_FLAG_PRIVATE_DEFINED, "Defined private"}, {MAC_REF_FLAG_PRIVATE_UNDEFINED_NON_LAZY, "Private undefined non lazy"}, {MAC_REF_FLAG_PRIVATE_UNDEFINED_LAZY, "Private undefined lazy"} }; // Symbol descriptor flag names SIntTxt MacSymbolDescriptorFlagNames[] = { {MAC_REFERENCED_DYNAMICALLY, "Referenced dynamically"}, // {MAC_N_DESC_DISCARDED, "Discarded"}, {MAC_N_NO_DEAD_STRIP, "Don't dead-strip"}, {MAC_N_WEAK_REF, "Weak external"}, {MAC_N_WEAK_DEF, "Weak public"} }; // Class CMACHO members: // Constructor template CMACHO::CMACHO() { // Set everything to zero memset(this, 0, sizeof(*this)); } template void CMACHO::ParseFile(){ // Load and parse file buffer FileHeader = *(TMAC_header*)Buf(); // Copy file header // Loop through file commands uint32 cmd, cmdsize; uint32 currentoffset = sizeof(TMAC_header); for (uint32 i = 1; i <= FileHeader.ncmds; i++) { if (currentoffset >= this->GetDataSize()) { err.submit(2016); return; } uint8 * currentp = (uint8*)(Buf() + currentoffset); cmd = ((MAC_load_command*)currentp) -> cmd; cmdsize = ((MAC_load_command*)currentp) -> cmdsize; // Interpret specific command type switch(cmd) { case MAC_LC_SEGMENT: { if (WordSize != 32) err.submit(2320); // mixed segment size MAC_segment_command_32 * sh = (MAC_segment_command_32*)currentp; SegmentOffset = sh->fileoff; // File offset of segment SegmentSize = sh->filesize; // Size of segment NumSections = sh->nsects; // Number of sections SectionHeaderOffset = currentoffset + sizeof(TMAC_segment_command); // File offset of section headers if (!ImageBase && strcmp(sh->segname, "__TEXT")==0) ImageBase = sh->vmaddr; // Find image base break;} case MAC_LC_SEGMENT_64: { if (WordSize != 64) err.submit(2320); // mixed segment size MAC_segment_command_64 * sh = (MAC_segment_command_64*)currentp; SegmentOffset = (uint32)sh->fileoff; // File offset of segment SegmentSize = (uint32)sh->filesize; // Size of segment NumSections = sh->nsects; // Number of sections SectionHeaderOffset = currentoffset + sizeof(TMAC_segment_command); // File offset of section headers if (!ImageBase && strcmp(sh->segname, "__TEXT")==0) ImageBase = sh->vmaddr; // Find image base break;} case MAC_LC_SYMTAB: { MAC_symtab_command * sh = (MAC_symtab_command*)currentp; SymTabOffset = sh->symoff; // File offset of symbol table SymTabNumber = sh->nsyms; // Number of entries in symbol table StringTabOffset = sh->stroff; // File offset of string table StringTabSize = sh->strsize; // Size of string table break;} case MAC_LC_DYSYMTAB: { MAC_dysymtab_command * sh = (MAC_dysymtab_command*)currentp; ilocalsym = sh->ilocalsym; // index to local symbols nlocalsym = sh->nlocalsym; // number of local symbols iextdefsym = sh->iextdefsym; // index to externally defined symbols nextdefsym = sh->nextdefsym; // number of externally defined symbols iundefsym = sh->iundefsym; // index to undefined symbols nundefsym = sh->nundefsym; // number of undefined symbols IndirectSymTabOffset = sh->indirectsymoff;// file offset to the indirect symbol table IndirectSymTabNumber = sh->nindirectsyms; // number of indirect symbol table entries break;} } currentoffset += cmdsize; } } // Debug dump template void CMACHO::Dump(int options) { uint32 icmd; // Command index int32 isec1; // Section index within segment int32 isec2; // Section index global int32 nsect; // Number of sections in segment if (options & DUMP_FILEHDR) { // File header printf("\nDump of Mach-O file %s", FileName); printf("\n-----------------------------------------------"); printf("\nFile size: 0x%X", this->GetDataSize()); printf("\nFile header:"); printf("\n CPU type: %s, subtype: %s", Lookup(MacMachineNames, FileHeader.cputype), Lookup(MacCPUSubtypeNames, FileHeader.cpusubtype)); printf("\n File type: %s - %s", GetFileFormatName(FileType), Lookup(MacFileTypeNames, FileHeader.filetype)); printf("\n Number of load commands: %i, Size of commands: 0x%X, Flags: %X", FileHeader.ncmds, FileHeader.sizeofcmds, FileHeader.flags); } uint32 cmd; // Load command uint32 cmdsize; // Command size // Pointer to current position uint8 * currentp = (uint8*)(Buf() + sizeof(TMAC_header)); // Loop through file commands for (icmd = 1; icmd <= FileHeader.ncmds; icmd++) { cmd = ((MAC_load_command*)currentp) -> cmd; cmdsize = ((MAC_load_command*)currentp) -> cmdsize; if (options & DUMP_SECTHDR) { // Dump command header printf("\n\nCommand %i: %s, size: 0x%X", icmd, Lookup(MacCommandTypeNames, cmd), cmdsize); // Interpret specific command type switch(cmd) { case MAC_LC_SEGMENT: { MAC_segment_command_32 * sh = (MAC_segment_command_32*)currentp; printf("\n Name: %s, Memory address 0x%X, Memory size 0x%X" "\n File offset 0x%X, File size 0x%X, Maxprot 0x%X, Initprot 0x%X" "\n Number of sections %i, Flags 0x%X", sh->segname, sh->vmaddr, sh->vmsize, sh->fileoff, sh->filesize, sh->maxprot, sh->initprot, sh->nsects, sh->flags); break;} case MAC_LC_SEGMENT_64: { MAC_segment_command_64 * sh = (MAC_segment_command_64*)currentp; printf("\n Name: %s, \n Memory address 0x%08X%08X, Memory size 0x%08X%08X" "\n File offset 0x%08X%08X, File size 0x%08X%08X\n Maxprot 0x%X, Initprot 0x%X" "\n Number of sections %i, Flags 0x%X", sh->segname, (uint32)(sh->vmaddr>>32), (uint32)sh->vmaddr, (uint32)(sh->vmsize>>32), (uint32)sh->vmsize, (uint32)(sh->fileoff>>32), (uint32)sh->fileoff, (uint32)(sh->filesize>>32), (uint32)sh->filesize, sh->maxprot, sh->initprot, sh->nsects, sh->flags); break;} case MAC_LC_SYMTAB: { MAC_symtab_command * sh = (MAC_symtab_command*)currentp; printf("\n Symbol table offset 0x%X, number of symbols %i," "\n String table offset 0x%X, String table size 0x%X", sh->symoff, sh->nsyms, sh->stroff, sh->strsize); break;} case MAC_LC_DYSYMTAB: { MAC_dysymtab_command * sh = (MAC_dysymtab_command*)currentp; printf("\n Index to local symbols %i, number of local symbols %i," "\n Index to external symbols %i, number of external symbols %i," "\n Index to undefined symbols %i, number of undefined symbols %i," "\n File offset to TOC 0x%X, number of entries in TOC %i,", sh->ilocalsym, sh->nlocalsym, sh->iextdefsym, sh->nextdefsym, sh->iundefsym, sh->nundefsym, sh->tocoff, sh->ntoc); printf("\n File offset to module table 0x%X, Number of module table entries %i," "\n Offset to referenced symbol table 0x%X, Number of referenced symtab entries %i" "\n Offset to indirect symbol table 0x%X, Number of indirect symtab entries %i" "\n Offset to external relocation entries 0x%X, Number of external reloc. entries %i" "\n Offset to local relocation entries 0x%X, Number of local reloc. entries %i", sh->modtaboff, sh->nmodtab, sh->extrefsymoff, sh->nextrefsyms, sh->indirectsymoff, sh->nindirectsyms, sh->extreloff, sh->nextrel, sh->locreloff, sh->nlocrel); break;} } } currentp += cmdsize; } // Dump section headers if (options & DUMP_SECTHDR) { printf("\n\nSections:"); // Reset current pointer currentp = (uint8*)(Buf() + sizeof(TMAC_header)); isec2 = 0; // Loop through load commands for (icmd = 1; icmd <= FileHeader.ncmds; icmd++) { cmd = ((MAC_load_command*)currentp) -> cmd; cmdsize = ((MAC_load_command*)currentp) -> cmdsize; if (cmd == MAC_LC_SEGMENT) { // This is a 32-bit segment command // Number of sections in segment nsect = ((MAC_segment_command_32*)currentp) -> nsects; // Find first section header MAC_section_32 * sectp = (MAC_section_32*)(currentp + sizeof(MAC_segment_command_32)); // Loop through section headers for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) { printf("\n\nSection %i: Name: %s, Segment: %s.", ++isec2, sectp->sectname, sectp->segname); printf("\n Memory address 0x%X, Size 0x%X, File offset 0x%X" "\n Alignment %i, Reloc. ent. offset 0x%X, Num reloc. %i" "\n Flags 0x%X, reserved1 0x%X, reserved2 0x%X", sectp->addr, sectp->size, sectp->offset, 1 << sectp->align, sectp->reloff, sectp->nreloc, sectp->flags, sectp->reserved1, sectp->reserved2); if (sectp->nreloc && (options & DUMP_RELTAB)) { // Dump relocations printf("\n Relocations:"); if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;} MAC_relocation_info * relp = (MAC_relocation_info*)(Buf() + sectp->reloff); for (uint32 r = 1; r <= sectp->nreloc; r++, relp++) { if (relp->r_address & R_SCATTERED) { // scattered relocation into MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp; if (!(scatp->r_type & MAC32_RELOC_PAIR)) { printf ("\n Offset: 0x%X, Value: 0x%X, Length: %i, Scat. Type: %s", scatp->r_address, scatp->r_value, 1 << scatp->r_length, Lookup(Mac32RelocationTypeNames, scatp->r_type)); if (scatp->r_address < sectp->size) { printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+scatp->r_address)); } } else { // Second entry of a pair printf ("\n Offset2: 0x%X, Value2: 0x%X, Length2: %i", scatp->r_address, scatp->r_value, 1 << scatp->r_length); } if (scatp->r_pcrel) printf(", PC relative"); } else { // non-scattered if (relp->r_extern) printf ("\n Symbol number %i, ", relp->r_symbolnum); else printf ("\n Section: %i, ", relp->r_symbolnum); printf ("Offset: 0x%X, ", relp->r_address); if (relp->r_pcrel) printf ("PC relative, "); printf ("\n Length: %i, Extern: %i, Type: %s", 1 << relp->r_length, relp->r_extern, Lookup(Mac32RelocationTypeNames, relp->r_type)); if (relp->r_address < sectp->size) { printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+relp->r_address)); } } } } } } if (cmd == MAC_LC_SEGMENT_64) { // This is a 64-bit segment command // Number of sections in segment nsect = ((MAC_segment_command_64*)currentp) -> nsects; // Find first section header MAC_section_64 * sectp = (MAC_section_64*)(currentp + sizeof(MAC_segment_command_64)); // Loop through section headers for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) { printf("\n\nSection %i: Name: %s, Segment: %s.", ++isec2, sectp->sectname, sectp->segname); printf("\n Memory address 0x%X, Size 0x%X, File offset 0x%X" "\n Alignment %i, Reloc. ent. offset 0x%X, Num reloc. %i" "\n Flags 0x%X, reserved1 0x%X, reserved2 0x%X", (uint32)sectp->addr, (uint32)sectp->size, sectp->offset, 1 << sectp->align, sectp->reloff, sectp->nreloc, sectp->flags, sectp->reserved1, sectp->reserved2); if (sectp->nreloc && (options & DUMP_RELTAB)) { // Dump relocations printf("\n Relocations:"); MAC_relocation_info * relp = (MAC_relocation_info*)(Buf() + sectp->reloff); for (uint32 r = 1; r <= sectp->nreloc; r++, relp++) { if (relp->r_address & R_SCATTERED) { // scattered relocation into (not used in 64-bit Mach-O) MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp; if (!(scatp->r_type & MAC32_RELOC_PAIR)) { printf ("\n Unexpected scattered relocation. Offset: 0x%X, Value: 0x%X, Length: %i, Scat. Type: %s", scatp->r_address, scatp->r_value, 1 << scatp->r_length, Lookup(Mac64RelocationTypeNames, scatp->r_type)); if (scatp->r_address < sectp->size) { printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+scatp->r_address)); } } else { // Second entry of a pair printf ("\n Offset2: 0x%X, Value2: 0x%X, Length2: %i", scatp->r_address, scatp->r_value, 1 << scatp->r_length); } if (scatp->r_pcrel) printf(", PC relative"); } else { // non-scattered if (relp->r_extern) printf ("\n Symbol number %i, ", relp->r_symbolnum); else printf ("\n Section: %i, ", relp->r_symbolnum); printf ("Offset: 0x%X, ", relp->r_address); if (relp->r_pcrel) printf ("PC relative, "); printf ("\n Length: %i, Extern: %i, Type: %s", 1 << relp->r_length, relp->r_extern, Lookup(Mac64RelocationTypeNames, relp->r_type)); if (relp->r_type != MAC64_RELOC_SUBTRACTOR && relp->r_address < sectp->size) { // Print inline addend if (relp->r_length == 3) { // 8 bytes inline addend printf(", Inline: 0x%08X%08X", *(int32*)(Buf()+sectp->offset+relp->r_address+4), *(int32*)(Buf()+sectp->offset+relp->r_address)); } else { // 4 bytes inline addend printf(", Inline: 0x%08X", *(int32*)(Buf()+sectp->offset+relp->r_address)); } } } } } } } currentp += cmdsize; } } // pointer to string table char * strtab = (char*)(Buf() + StringTabOffset); // pointer to symbol table TMAC_nlist * symp0 = (TMAC_nlist*)(Buf() + SymTabOffset); // Dump symbol table if (options & DUMP_SYMTAB) { printf("\n\nSymbol table:"); uint32 i; TMAC_nlist * symp; // loop through symbol table for (i = 0, symp = symp0; i < SymTabNumber; i++, symp++) { // Header for first symbol of each category: (alphabetical within each category) if (i == ilocalsym && nlocalsym) printf("\n\n Local symbols:"); if (i == iextdefsym && nextdefsym) printf("\n\n Public symbols:"); if (i == iundefsym && nundefsym) printf("\n\n External symbols:"); if (symp->n_strx < StringTabSize && !(symp->n_type & MAC_N_STAB)) { printf("\n %2i %s, Section %i, Value 0x%X\n ", i, strtab + symp->n_strx, symp->n_sect, uint32(symp->n_value)); } else { printf("\n String table offset: 0x%X, Section %i, Value 0x%X\n ", symp->n_strx, symp->n_sect, uint32(symp->n_value)); } if (symp->n_type & MAC_N_STAB) { printf ("Debug symbol, stab = 0x%X, ", symp->n_type); } else { if (symp->n_type & MAC_N_PEXT) printf ("Private external (limited global scope), "); if (symp->n_type & MAC_N_EXT ) printf ("External, "); printf("%s", Lookup(MacSymbolTypeNames, symp->n_type & MAC_N_TYPE)); } printf("\n Reference type: %s, Flags: ", Lookup(MacSymbolReferenceTypeNames, symp->n_desc & MAC_REF_TYPE)); for (uint32 f = MAC_REFERENCED_DYNAMICALLY; f <= MAC_N_WEAK_DEF; f <<= 1) { if (symp->n_desc & f) { printf("%s, ", Lookup(MacSymbolDescriptorFlagNames, f)); } } } // Check if indirect symbol table is valid if (IndirectSymTabNumber && IndirectSymTabOffset + IndirectSymTabNumber*4 < this->GetDataSize()) { // Write indirect symbol table printf("\n\n Indirect symbols:"); // loop through indirect symbol table uint32 * IndSymip = (uint32*)(Buf() + IndirectSymTabOffset); for (i = 0; i < IndirectSymTabNumber; i++, IndSymip++) { // Check if index within symbol table if (*IndSymip >= SymTabNumber) { //err.submit(2016); printf("\n Unknown(0x%X)", *IndSymip); continue; } // Find record TMAC_nlist * pIndSym = symp0 + *IndSymip; // Find name uint32 StringIndex = pIndSym->n_strx; if (StringIndex >= StringTabSize) { err.submit(2035); continue; } // print name printf("\n %s", strtab + StringIndex); // print type, etc. printf(", type 0x%X, sect %i, desc 0x%X, val 0x%X", pIndSym->n_type, pIndSym->n_sect, pIndSym->n_desc, uint32(pIndSym->n_value)); } } } // Dump string table if (options & DUMP_STRINGTB) { printf("\n\nString table:"); uint32 str = 0, istr = 0; while (str < StringTabSize) { char * p = (char*)(Buf() + StringTabOffset + str); printf("\n %3i: %s", str, p); istr++; str += (uint32)strlen(p) + 1; } } } template void CMACHO::PublicNames(CMemoryBuffer * Strings, CSList * Index, int m) { // Make list of public names uint32 i; SStringEntry se; // Entry in Index // Interpret header: ParseFile(); // pointer to string table char * strtab = (char*)(Buf() + StringTabOffset); // loop through public symbol table TMAC_nlist * symp = (TMAC_nlist*)(Buf() + SymTabOffset + iextdefsym * sizeof(TMAC_nlist)); for (i = 0; i < nextdefsym; i++, symp++) { if (symp->n_strx < StringTabSize && !(symp->n_type & MAC_N_STAB)) { // Public symbol found se.Member = m; // Store name se.String = Strings->PushString(strtab + symp->n_strx); // Store name index Index->Push(se); } } } // Member functions for class MacSymbolTableBuilder template MacSymbolTableBuilder::MacSymbolTableBuilder() { // Constructor sorted = 0; } template void MacSymbolTableBuilder::AddSymbol(int OldIndex, const char * name, int type, int Desc, int section, MInt value) { // Add symbol to list MacSymbolRecord rec; memset(&rec, 0, sizeof(rec)); // Set to zero /* !! if (GetNumEntries() == 0) { // First record must indicate empty string rec.Name = StringBuffer.PushString(""); // Empty string Push(&rec, sizeof(rec)); // Put empty record in memory buffer } */ rec.n_type = (uint8)type; // Copy values rec.n_sect = (uint8)section; rec.n_desc = (int16)Desc; rec.n_value = value; rec.Name = StringBuffer.PushString(name); // Copy name and store index rec.OldIndex = OldIndex; // Remember old index Push(&rec, sizeof(rec)); // Put in memory buffer sorted = 0; // Remember not sorted } template void MacSymbolTableBuilder::SortList() { // Sort the list if (sorted) return; // allready sorted MacSymbolRecord * p = (MacSymbolRecord*)Buf(); // Point to list // Simple Shell sort with Sedgewick gaps: int i, j, k, gap, n = (int)GetNumEntries(); for (k = 15; k >= 0; k--) { gap = (1 << 2 * k) | (3 << k >> 1) | 1; // Sedgewick gap grants O(N^4/3) for (i = gap; i < n; i++) { MacSymbolRecord key = p[i]; char * strkey = StringBuffer.Buf() + key.Name; for (j = i - gap; j >= 0 && strcmp(strkey, StringBuffer.Buf() + p[j].Name) < 0; j -= gap) { p[j + gap] = p[j]; } p[j + gap] = key; } } sorted = 1; } template int MacSymbolTableBuilder::TranslateIndex(int OldIndex) { // Translate old index to new index (0-based) // Returns -1 if not found // Don't sort list. This would change indices if __mh_executer_header added later // if (!sorted) SortList(); MacSymbolRecord * p = (MacSymbolRecord*)Buf(); // Point to list // Search through list for OldIndex for (int i = 0; i < (int)GetNumEntries(); i++) { if (p[i].OldIndex == OldIndex) { // Match found return i; } } // Not found return -1; } template void MacSymbolTableBuilder::StoreList(CMemoryBuffer * SymbolTable, CMemoryBuffer * StringTable) { // Store sorted list in buffers // Don't sort list unless commanded to do so. Will mess up indices // if (!sorted) SortList(); // Make sure list is sorted MacSymbolRecord * p = (MacSymbolRecord*)Buf(); // Point to list for (uint32 i = 0; i < GetNumEntries(); i++, p++) { p->n_strx = StringTable->PushString(StringBuffer.Buf()+p->Name); // Put name in string table SymbolTable->Push(p, sizeof(TMAC_nlist)); // Store only the TMAC_nlist part of the record in SymbolTable } } template int MacSymbolTableBuilder::Search(const char * name) { // Search for name. Return -1 if not found. MacSymbolRecord * p = (MacSymbolRecord*)Buf(); // Point to list for (int i = 0; i < (int)GetNumEntries(); i++) { if (strcmp(StringBuffer.Buf()+p[i].Name, name) == 0) { return i; // Found } } return -1; // Not found } template MacSymbolRecord & MacSymbolTableBuilder::operator[] (uint32 i) { // Access member uint32 Offset = i * sizeof(MacSymbolRecord); if (i + sizeof(MacSymbolRecord) > this->GetDataSize()) { err.submit(9003); Offset = 0; } return Get >(Offset); } /****** Class CMACUNIV for parsing Macintosh universal binary *************/ CMACUNIV::CMACUNIV() { // Default constructor } void CMACUNIV::Go(int options) { // Apply command options to all components // Check file size if (GetDataSize() < 28) return; // Read number of components uint32 NumComponents = EndianChange(Get(0).num_arch); if (NumComponents == 0 || NumComponents > 10) { // Number of components too big or too small err.submit(2701, NumComponents); return; } uint32 i; // Component number uint32 fo; // File offset of component pointer CConverter ComponentBuffer; // Used for converting component CConverter OutputBuffer; // Temporary storage of output file int DesiredWordSize = cmd.DesiredWordSize; // Desired word size, if specified on command line // Loop through components for (i = 0, fo = sizeof(MAC_UNIV_FAT_HEADER); i < NumComponents; i++, fo += sizeof(MAC_UNIV_FAT_ARCH)) { // Get component pointer MAC_UNIV_FAT_ARCH & ComponentPointer = Get(fo); // Get offset and size of component uint32 ComponentOffset = EndianChange(ComponentPointer.offset); uint32 ComponentSize = EndianChange(ComponentPointer.size); // Check within range if (ComponentOffset + ComponentSize > GetDataSize()) { err.submit(2016); return; } // Put component into buffer ComponentBuffer.Reset(); ComponentBuffer.Push(Buf() + ComponentOffset, ComponentSize); // Indicate component printf("\n\n\nComponent file number %i:\n", i + 1); // Check type uint32 ComponentType = ComponentBuffer.GetFileType(); if (DesiredWordSize && DesiredWordSize != ComponentBuffer.WordSize) { err.submit(1151, ComponentBuffer.WordSize); } else if (ComponentType != FILETYPE_MACHO_LE) { // Format not supported printf(" Format not supported: %s", GetFileFormatName(ComponentType)); } else { // Format OK. Handle component if (cmd.DumpOptions == 0 && OutputBuffer.GetDataSize()) { // More than one component that can be converted err.submit(1150); } else { // Transfer filenames ComponentBuffer.FileName = FileName; ComponentBuffer.OutputFileName = OutputFileName; // Do command ComponentBuffer.Go(); // Is there an output file? if (cmd.DumpOptions == 0) { // Save output file ComponentBuffer >> OutputBuffer; } } } } // Is there an output file? if (OutputBuffer.GetDataSize()) { // Take over output file and skip remaining components *this << OutputBuffer; } } // Make template instances for 32 and 64 bits template class CMACHO; template class CMACHO; template class MacSymbolTableBuilder; template class MacSymbolTableBuilder;