Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************    macho.cpp    *******************************
  2. * Author:        Agner Fog
  3. * Date created:  2007-01-06
  4. * Last modified: 2008-06-02
  5. * Project:       objconv
  6. * Module:        macho.cpp
  7. * Description:
  8. * Module for reading Mach-O files
  9. *
  10. * Class CMACHO is used for reading, interpreting and dumping Mach-O files.
  11. *
  12. * Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
  13. *****************************************************************************/
  14. #include "stdafx.h"
  15.  
  16. // Machine names
  17. SIntTxt MacMachineNames[] = {
  18.    {MAC_CPU_TYPE_I386,      "Intel 32 bit"},
  19.    {MAC_CPU_TYPE_X86_64,    "Intel 64 bit"},
  20.    {MAC_CPU_TYPE_ARM,       "Arm"},
  21.    {MAC_CPU_TYPE_SPARC,     "Sparc"},
  22.    {MAC_CPU_TYPE_POWERPC,   "Power PC 32 bit"},
  23.    {MAC_CPU_TYPE_POWERPC64, "Power PC 64 bit"}
  24. };
  25.  
  26. // CPU subtype names
  27. SIntTxt MacCPUSubtypeNames[] = {
  28.    {MAC_CPU_SUBTYPE_POWERPC_ALL,  "Power PC All"},
  29.    {MAC_CPU_SUBTYPE_I386_ALL,     "Intel All"}
  30. };
  31.  
  32. // File type names
  33. SIntTxt MacFileTypeNames[] = {
  34.    {MAC_OBJECT,     "Relocatable object file"},
  35.    {MAC_EXECUTE,    "demand paged executable file"},
  36.    {MAC_FVMLIB,     "fixed VM shared library file"},
  37.    {MAC_CORE,       "core file"},
  38.    {MAC_PRELOAD,    "preloaded executable file"},
  39.    {MAC_DYLIB,      "dynamicly bound shared library file"},
  40.    {MAC_DYLINKER,   "dynamic link editor"},
  41.    {MAC_BUNDLE,     "dynamicly bound bundle file"}
  42. };
  43.  
  44. // Command type names
  45. SIntTxt MacCommandTypeNames[] = {
  46.    {MAC_LC_SEGMENT,        "Segment"},
  47.    {MAC_LC_SYMTAB,         "Symbol table"},
  48.    {MAC_LC_SYMSEG,         "gdb symbol table info (obsolete)"},
  49.    {MAC_LC_THREAD,         "thread"},
  50.    {MAC_LC_UNIXTHREAD,     "unix thread"},
  51.    {MAC_LC_LOADFVMLIB,     "load a specified fixed VM shared library"},
  52.    {MAC_LC_IDFVMLIB,       "fixed VM shared library identification"},
  53.    {MAC_LC_IDENT,          "object identification info (obsolete)"},
  54.    {MAC_LC_FVMFILE,        "fixed VM file inclusion (internal use)"},
  55.    {MAC_LC_PREPAGE,        "prepage command (internal use)"},
  56.    {MAC_LC_DYSYMTAB,       "dynamic link-edit symbol table info"},
  57.    {MAC_LC_LOAD_DYLIB,     "load a dynamicly linked shared library"},
  58.    {MAC_LC_ID_DYLIB,       "dynamicly linked shared lib identification"},
  59.    {MAC_LC_LOAD_DYLINKER,  "load a dynamic linker"},
  60.    {MAC_LC_ID_DYLINKER,    "dynamic linker identification"},
  61.    {MAC_LC_PREBOUND_DYLIB, "modules prebound for a dynamicly linked shared library"},
  62.    {MAC_LC_ROUTINES,       "image routines"},
  63.    {MAC_LC_SUB_FRAMEWORK,  "sub framework"},
  64.    {MAC_LC_SUB_UMBRELLA,   "sub umbrella"},
  65.    {MAC_LC_SUB_CLIENT,     "sub client"},
  66.    {MAC_LC_SUB_LIBRARY,    "sub library"},
  67.    {MAC_LC_TWOLEVEL_HINTS, "two-level namespace lookup hints"},
  68.    {MAC_LC_PREBIND_CKSUM,  "prebind checksum"},
  69.    {MAC_LC_LOAD_WEAK_DYLIB&0xFF, "load a dynamically linked shared library, all symbols weak"},
  70.    {MAC_LC_SEGMENT_64,     "64-bit segment"},
  71.    {MAC_LC_ROUTINES_64,    "64-bit image routine"},
  72.    {MAC_LC_UUID,           "uuid"}
  73. };
  74.  
  75. // Relocation type names, 32 bit
  76. SIntTxt Mac32RelocationTypeNames[] = {
  77.    {MAC32_RELOC_VANILLA,        "Generic"},
  78.    {MAC32_RELOC_PAIR,           "Second entry of a pair"},
  79.    {MAC32_RELOC_SECTDIFF,       "Section diff"},
  80.    {MAC32_RELOC_PB_LA_PTR,      "Prebound lazy "},
  81.    {MAC32_RELOC_LOCAL_SECTDIFF, "SectDif local"}
  82. };
  83.  
  84. // Relocation type names, 64 bit
  85. SIntTxt Mac64RelocationTypeNames[] = {
  86.    {MAC64_RELOC_UNSIGNED,    "absolute address"},
  87.    {MAC64_RELOC_SIGNED,      "signed 32-bit displ."},
  88.    {MAC64_RELOC_BRANCH,      "Rel. jump 32-bit displ."},
  89.    {MAC64_RELOC_GOT_LOAD,    "MOVQ load of a GOT entry"},
  90.    {MAC64_RELOC_GOT,         "other GOT reference"},
  91.    {MAC64_RELOC_SUBTRACTOR,  "Subtractor"},
  92.    {MAC64_RELOC_SIGNED_1,    "signed 32-bit displacement with -1 addend"},
  93.    {MAC64_RELOC_SIGNED_2,    "signed 32-bit displacement with -2 addend"},
  94.    {MAC64_RELOC_SIGNED_4,    "signed 32-bit displacement with -4 addend"}
  95. };
  96.  
  97. // Symbol type names
  98. SIntTxt MacSymbolTypeNames[] = {
  99.    {MAC_N_UNDF,    "Undefined, no section"},
  100.    {MAC_N_ABS,     "Absolute, no section"},
  101.    {MAC_N_SECT,    "Defined"},
  102.    {MAC_N_PBUD,    "Prebound undefined (defined in a dylib)"},
  103.    {MAC_N_INDR,    "Indirect"}
  104. };
  105.  
  106. // Symbol reference type names
  107. SIntTxt MacSymbolReferenceTypeNames[] = {
  108.    {MAC_REF_FLAG_UNDEFINED_NON_LAZY,         "External non lazy"},
  109.    {MAC_REF_FLAG_UNDEFINED_LAZY,             "External lazy (function call)"},
  110.    {MAC_REF_FLAG_DEFINED,                    "Defined public"},
  111.    {MAC_REF_FLAG_PRIVATE_DEFINED,            "Defined private"},
  112.    {MAC_REF_FLAG_PRIVATE_UNDEFINED_NON_LAZY, "Private undefined non lazy"},
  113.    {MAC_REF_FLAG_PRIVATE_UNDEFINED_LAZY,     "Private undefined lazy"}
  114. };
  115.  
  116. // Symbol descriptor flag names
  117. SIntTxt MacSymbolDescriptorFlagNames[] = {
  118.    {MAC_REFERENCED_DYNAMICALLY, "Referenced dynamically"},
  119. // {MAC_N_DESC_DISCARDED,       "Discarded"},
  120.    {MAC_N_NO_DEAD_STRIP,        "Don't dead-strip"},
  121.    {MAC_N_WEAK_REF,             "Weak external"},
  122.    {MAC_N_WEAK_DEF,             "Weak public"}
  123. };
  124.  
  125.  
  126.  
  127. // Class CMACHO members:
  128. // Constructor
  129. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  130. CMACHO<MACSTRUCTURES>::CMACHO() {
  131.    // Set everything to zero
  132.    memset(this, 0, sizeof(*this));
  133. }
  134.  
  135. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  136. void CMACHO<MACSTRUCTURES>::ParseFile(){
  137.    // Load and parse file buffer
  138.    FileHeader = *(TMAC_header*)Buf();   // Copy file header
  139.  
  140.    // Loop through file commands
  141.    uint32 cmd, cmdsize;
  142.    uint32 currentoffset = sizeof(TMAC_header);
  143.    for (uint32 i = 1; i <= FileHeader.ncmds; i++) {
  144.       if (currentoffset >= this->GetDataSize()) {
  145.          err.submit(2016); return;
  146.       }
  147.       uint8 * currentp = (uint8*)(Buf() + currentoffset);
  148.       cmd     = ((MAC_load_command*)currentp) -> cmd;
  149.       cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
  150.       // Interpret specific command type
  151.       switch(cmd) {
  152.          case MAC_LC_SEGMENT: {
  153.             if (WordSize != 32) err.submit(2320); // mixed segment size
  154.             MAC_segment_command_32 * sh = (MAC_segment_command_32*)currentp;
  155.             SegmentOffset = sh->fileoff;              // File offset of segment
  156.             SegmentSize = sh->filesize;               // Size of segment
  157.             NumSections = sh->nsects;                 // Number of sections
  158.             SectionHeaderOffset = currentoffset + sizeof(TMAC_segment_command); // File offset of section headers
  159.             if (!ImageBase && strcmp(sh->segname, "__TEXT")==0) ImageBase = sh->vmaddr; // Find image base
  160.             break;}
  161.  
  162.          case MAC_LC_SEGMENT_64: {
  163.             if (WordSize != 64) err.submit(2320); // mixed segment size
  164.             MAC_segment_command_64 * sh = (MAC_segment_command_64*)currentp;
  165.             SegmentOffset = (uint32)sh->fileoff;      // File offset of segment
  166.             SegmentSize = (uint32)sh->filesize;       // Size of segment
  167.             NumSections = sh->nsects;                 // Number of sections
  168.             SectionHeaderOffset = currentoffset + sizeof(TMAC_segment_command); // File offset of section headers
  169.             if (!ImageBase && strcmp(sh->segname, "__TEXT")==0) ImageBase = sh->vmaddr; // Find image base
  170.             break;}
  171.  
  172.          case MAC_LC_SYMTAB: {
  173.             MAC_symtab_command * sh = (MAC_symtab_command*)currentp;
  174.             SymTabOffset = sh->symoff;                // File offset of symbol table
  175.             SymTabNumber = sh->nsyms;                 // Number of entries in symbol table
  176.             StringTabOffset = sh->stroff;             // File offset of string table
  177.             StringTabSize = sh->strsize;              // Size of string table
  178.             break;}
  179.  
  180.          case MAC_LC_DYSYMTAB: {
  181.             MAC_dysymtab_command * sh = (MAC_dysymtab_command*)currentp;
  182.             ilocalsym = sh->ilocalsym;                 // index to local symbols
  183.             nlocalsym = sh->nlocalsym;                 // number of local symbols
  184.             iextdefsym = sh->iextdefsym;                    // index to externally defined symbols
  185.             nextdefsym = sh->nextdefsym;                    // number of externally defined symbols
  186.             iundefsym = sh->iundefsym;                 // index to undefined symbols
  187.             nundefsym = sh->nundefsym;                 // number of undefined symbols
  188.             IndirectSymTabOffset = sh->indirectsymoff;// file offset to the indirect symbol table
  189.             IndirectSymTabNumber = sh->nindirectsyms; // number of indirect symbol table entries
  190.             break;}
  191.       }
  192.       currentoffset += cmdsize;
  193.    }
  194. }
  195.  
  196. // Debug dump
  197. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  198. void CMACHO<MACSTRUCTURES>::Dump(int options) {
  199.    uint32 icmd;                        // Command index
  200.    int32  isec1;                       // Section index within segment
  201.    int32  isec2;                       // Section index global
  202.    int32  nsect;                        // Number of sections in segment
  203.  
  204.    if (options & DUMP_FILEHDR) {
  205.       // File header
  206.       printf("\nDump of Mach-O file %s", FileName);
  207.       printf("\n-----------------------------------------------");
  208.       printf("\nFile size: 0x%X", this->GetDataSize());
  209.       printf("\nFile header:");
  210.       printf("\n  CPU type: %s, subtype: %s",
  211.          Lookup(MacMachineNames, FileHeader.cputype),
  212.          Lookup(MacCPUSubtypeNames, FileHeader.cpusubtype));
  213.      
  214.       printf("\n  File type: %s - %s",
  215.          GetFileFormatName(FileType), Lookup(MacFileTypeNames, FileHeader.filetype));
  216.  
  217.       printf("\n  Number of load commands: %i, Size of commands: 0x%X, Flags: %X",
  218.          FileHeader.ncmds, FileHeader.sizeofcmds, FileHeader.flags);
  219.    }
  220.  
  221.    uint32 cmd;                         // Load command
  222.    uint32 cmdsize;                     // Command size
  223.    // Pointer to current position
  224.    uint8 * currentp = (uint8*)(Buf() + sizeof(TMAC_header));
  225.  
  226.    // Loop through file commands
  227.    for (icmd = 1; icmd <= FileHeader.ncmds; icmd++) {
  228.       cmd     = ((MAC_load_command*)currentp) -> cmd;
  229.       cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
  230.  
  231.       if (options & DUMP_SECTHDR) {
  232.          // Dump command header
  233.          printf("\n\nCommand %i: %s, size: 0x%X", icmd,
  234.          Lookup(MacCommandTypeNames, cmd), cmdsize);
  235.  
  236.          // Interpret specific command type
  237.          switch(cmd) {
  238.             case MAC_LC_SEGMENT: {
  239.                MAC_segment_command_32 * sh = (MAC_segment_command_32*)currentp;
  240.                printf("\n  Name: %s, Memory address 0x%X, Memory size 0x%X"
  241.                   "\n  File offset 0x%X, File size 0x%X, Maxprot 0x%X, Initprot 0x%X"
  242.                   "\n  Number of sections %i, Flags 0x%X",
  243.                   sh->segname, sh->vmaddr, sh->vmsize,
  244.                   sh->fileoff, sh->filesize, sh->maxprot, sh->initprot,
  245.                   sh->nsects, sh->flags);
  246.                break;}
  247.  
  248.             case MAC_LC_SEGMENT_64: {
  249.                MAC_segment_command_64 * sh = (MAC_segment_command_64*)currentp;
  250.                printf("\n  Name: %s, \n  Memory address 0x%08X%08X, Memory size 0x%08X%08X"
  251.                   "\n  File offset 0x%08X%08X, File size 0x%08X%08X\n  Maxprot 0x%X, Initprot 0x%X"
  252.                   "\n  Number of sections %i, Flags 0x%X",
  253.                   sh->segname, (uint32)(sh->vmaddr>>32), (uint32)sh->vmaddr,
  254.                   (uint32)(sh->vmsize>>32), (uint32)sh->vmsize,
  255.                   (uint32)(sh->fileoff>>32), (uint32)sh->fileoff,
  256.                   (uint32)(sh->filesize>>32), (uint32)sh->filesize,
  257.                   sh->maxprot, sh->initprot,
  258.                   sh->nsects, sh->flags);
  259.                break;}
  260.  
  261.             case MAC_LC_SYMTAB: {
  262.                MAC_symtab_command * sh = (MAC_symtab_command*)currentp;
  263.                printf("\n  Symbol table offset 0x%X, number of symbols %i,"
  264.                   "\n  String table offset 0x%X, String table size 0x%X",
  265.                   sh->symoff, sh->nsyms, sh->stroff, sh->strsize);
  266.                break;}
  267.  
  268.             case MAC_LC_DYSYMTAB: {
  269.                MAC_dysymtab_command * sh = (MAC_dysymtab_command*)currentp;
  270.                printf("\n  Index to local symbols %i, number of local symbols %i,"
  271.                   "\n  Index to external symbols %i, number of external symbols %i,"
  272.                   "\n  Index to undefined symbols %i, number of undefined symbols %i,"
  273.                   "\n  File offset to TOC 0x%X, number of entries in TOC %i,",
  274.                   sh->ilocalsym, sh->nlocalsym, sh->iextdefsym, sh->nextdefsym,
  275.                   sh->iundefsym, sh->nundefsym, sh->tocoff, sh->ntoc);
  276.                printf("\n  File offset to module table 0x%X, Number of module table entries %i,"
  277.                   "\n  Offset to referenced symbol table 0x%X, Number of referenced symtab entries %i"
  278.                   "\n  Offset to indirect symbol table 0x%X, Number of indirect symtab entries %i"
  279.                   "\n  Offset to external relocation entries 0x%X, Number of external reloc. entries %i"
  280.                   "\n  Offset to local relocation entries 0x%X, Number of local reloc. entries %i",
  281.                   sh->modtaboff, sh->nmodtab, sh->extrefsymoff, sh->nextrefsyms,
  282.                   sh->indirectsymoff, sh->nindirectsyms, sh->extreloff, sh->nextrel,
  283.                   sh->locreloff, sh->nlocrel); 
  284.                break;}
  285.          }
  286.  
  287.       }
  288.       currentp += cmdsize;
  289.    }
  290.  
  291.    // Dump section headers
  292.    if (options & DUMP_SECTHDR) {
  293.       printf("\n\nSections:");
  294.  
  295.       // Reset current pointer
  296.       currentp = (uint8*)(Buf() + sizeof(TMAC_header));
  297.       isec2 = 0;
  298.  
  299.       // Loop through load commands
  300.       for (icmd = 1; icmd <= FileHeader.ncmds; icmd++) {
  301.          cmd     = ((MAC_load_command*)currentp) -> cmd;
  302.          cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
  303.  
  304.          if (cmd == MAC_LC_SEGMENT) {
  305.             // This is a 32-bit segment command
  306.             // Number of sections in segment
  307.             nsect   = ((MAC_segment_command_32*)currentp) -> nsects;
  308.  
  309.             // Find first section header
  310.             MAC_section_32 * sectp = (MAC_section_32*)(currentp + sizeof(MAC_segment_command_32));
  311.  
  312.             // Loop through section headers
  313.             for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) {
  314.                printf("\n\nSection %i: Name: %s, Segment: %s.",
  315.                   ++isec2, sectp->sectname, sectp->segname);
  316.                printf("\n  Memory address 0x%X, Size 0x%X, File offset 0x%X"
  317.                   "\n  Alignment %i, Reloc. ent. offset 0x%X, Num reloc. %i"
  318.                   "\n  Flags 0x%X, reserved1 0x%X, reserved2 0x%X",
  319.                   sectp->addr, sectp->size, sectp->offset, 1 << sectp->align,
  320.                   sectp->reloff, sectp->nreloc, sectp->flags,
  321.                   sectp->reserved1, sectp->reserved2);
  322.  
  323.                if (sectp->nreloc && (options & DUMP_RELTAB)) {
  324.                   // Dump relocations
  325.                   printf("\n  Relocations:");
  326.                   if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;}
  327.                   MAC_relocation_info * relp = (MAC_relocation_info*)(Buf() + sectp->reloff);
  328.                   for (uint32 r = 1; r <= sectp->nreloc; r++, relp++) {
  329.                      if (relp->r_address & R_SCATTERED) {
  330.                         // scattered relocation into
  331.                         MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp;
  332.  
  333.                         if (!(scatp->r_type & MAC32_RELOC_PAIR)) {
  334.                            printf ("\n    Offset: 0x%X, Value: 0x%X, Length: %i, Scat. Type: %s",
  335.                               scatp->r_address, scatp->r_value, 1 << scatp->r_length,
  336.                               Lookup(Mac32RelocationTypeNames, scatp->r_type));
  337.                            if (scatp->r_address < sectp->size) {
  338.                               printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+scatp->r_address));
  339.                            }
  340.                         }
  341.                         else {
  342.                            // Second entry of a pair
  343.                            printf ("\n     Offset2: 0x%X, Value2: 0x%X, Length2: %i",
  344.                               scatp->r_address, scatp->r_value, 1 << scatp->r_length);
  345.                         }
  346.                         if (scatp->r_pcrel) printf(", PC relative");
  347.                      }
  348.                      else {
  349.                         // non-scattered
  350.                         if (relp->r_extern) printf ("\n    Symbol number %i, ", relp->r_symbolnum);
  351.                         else printf ("\n    Section: %i, ", relp->r_symbolnum);
  352.                         printf ("Offset: 0x%X, ", relp->r_address);
  353.                         if (relp->r_pcrel) printf ("PC relative, ");
  354.                         printf ("\n     Length: %i, Extern: %i, Type: %s",
  355.                            1 << relp->r_length, relp->r_extern,
  356.                            Lookup(Mac32RelocationTypeNames, relp->r_type));
  357.                         if (relp->r_address < sectp->size) {
  358.                            printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+relp->r_address));
  359.                         }
  360.                      }
  361.                   }
  362.                }
  363.             }
  364.          }
  365.          if (cmd == MAC_LC_SEGMENT_64) {
  366.             // This is a 64-bit segment command
  367.             // Number of sections in segment
  368.             nsect   = ((MAC_segment_command_64*)currentp) -> nsects;
  369.  
  370.             // Find first section header
  371.             MAC_section_64 * sectp = (MAC_section_64*)(currentp + sizeof(MAC_segment_command_64));
  372.  
  373.             // Loop through section headers
  374.             for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) {
  375.                printf("\n\nSection %i: Name: %s, Segment: %s.",
  376.                   ++isec2, sectp->sectname, sectp->segname);
  377.                printf("\n  Memory address 0x%X, Size 0x%X, File offset 0x%X"
  378.                   "\n  Alignment %i, Reloc. ent. offset 0x%X, Num reloc. %i"
  379.                   "\n  Flags 0x%X, reserved1 0x%X, reserved2 0x%X",
  380.                   (uint32)sectp->addr, (uint32)sectp->size, sectp->offset, 1 << sectp->align,
  381.                   sectp->reloff, sectp->nreloc, sectp->flags,
  382.                   sectp->reserved1, sectp->reserved2);
  383.  
  384.                if (sectp->nreloc && (options & DUMP_RELTAB)) {
  385.                   // Dump relocations
  386.                   printf("\n  Relocations:");
  387.                   MAC_relocation_info * relp = (MAC_relocation_info*)(Buf() + sectp->reloff);
  388.                   for (uint32 r = 1; r <= sectp->nreloc; r++, relp++) {
  389.                      if (relp->r_address & R_SCATTERED) {
  390.                         // scattered relocation into (not used in 64-bit Mach-O)
  391.                         MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp;
  392.                         if (!(scatp->r_type & MAC32_RELOC_PAIR)) {
  393.                            printf ("\n    Unexpected scattered relocation. Offset: 0x%X, Value: 0x%X, Length: %i, Scat. Type: %s",
  394.                               scatp->r_address, scatp->r_value, 1 << scatp->r_length,
  395.                               Lookup(Mac64RelocationTypeNames, scatp->r_type));
  396.                            if (scatp->r_address < sectp->size) {
  397.                               printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+scatp->r_address));
  398.                            }
  399.                         }
  400.                         else {
  401.                            // Second entry of a pair
  402.                            printf ("\n     Offset2: 0x%X, Value2: 0x%X, Length2: %i",
  403.                               scatp->r_address, scatp->r_value, 1 << scatp->r_length);
  404.                         }
  405.                         if (scatp->r_pcrel) printf(", PC relative");
  406.                      }
  407.                      else {
  408.                         // non-scattered
  409.                         if (relp->r_extern) printf ("\n    Symbol number %i, ", relp->r_symbolnum);
  410.                         else printf ("\n    Section: %i, ", relp->r_symbolnum);
  411.                         printf ("Offset: 0x%X, ", relp->r_address);
  412.                         if (relp->r_pcrel) printf ("PC relative, ");
  413.                         printf ("\n     Length: %i, Extern: %i, Type: %s",
  414.                            1 << relp->r_length, relp->r_extern,
  415.                            Lookup(Mac64RelocationTypeNames, relp->r_type));
  416.                         if (relp->r_type != MAC64_RELOC_SUBTRACTOR && relp->r_address < sectp->size) {
  417.                            // Print inline addend
  418.                            if (relp->r_length == 3) {
  419.                               // 8 bytes inline addend
  420.                               printf(", Inline: 0x%08X%08X", *(int32*)(Buf()+sectp->offset+relp->r_address+4), *(int32*)(Buf()+sectp->offset+relp->r_address));
  421.                            }
  422.                            else {
  423.                               // 4 bytes inline addend
  424.                               printf(", Inline: 0x%08X", *(int32*)(Buf()+sectp->offset+relp->r_address));
  425.                            }
  426.                         }
  427.                      }
  428.                   }
  429.                }
  430.             }
  431.          }
  432.          currentp += cmdsize;
  433.       }
  434.    }
  435.  
  436.    // pointer to string table
  437.    char * strtab = (char*)(Buf() + StringTabOffset);
  438.    // pointer to symbol table
  439.    TMAC_nlist * symp0 = (TMAC_nlist*)(Buf() + SymTabOffset);
  440.  
  441.    // Dump symbol table
  442.    if (options & DUMP_SYMTAB) {
  443.       printf("\n\nSymbol table:");
  444.       uint32 i;
  445.       TMAC_nlist * symp;
  446.  
  447.       // loop through symbol table
  448.       for (i = 0, symp = symp0; i < SymTabNumber; i++, symp++) {
  449.  
  450.          // Header for first symbol of each category: (alphabetical within each category)
  451.          if (i == ilocalsym && nlocalsym)   printf("\n\n  Local symbols:");
  452.          if (i == iextdefsym && nextdefsym) printf("\n\n  Public symbols:");
  453.          if (i == iundefsym && nundefsym)   printf("\n\n  External symbols:");
  454.  
  455.          if (symp->n_strx < StringTabSize && !(symp->n_type & MAC_N_STAB)) {
  456.             printf("\n  %2i %s, Section %i, Value 0x%X\n    ",
  457.                i, strtab + symp->n_strx, symp->n_sect, uint32(symp->n_value));
  458.          }
  459.          else {
  460.             printf("\n  String table offset: 0x%X, Section %i, Value 0x%X\n    ",
  461.                symp->n_strx, symp->n_sect, uint32(symp->n_value));
  462.          }
  463.  
  464.          if (symp->n_type & MAC_N_STAB) {
  465.             printf ("Debug symbol, stab = 0x%X, ", symp->n_type);
  466.          }
  467.          else {
  468.             if (symp->n_type & MAC_N_PEXT) printf ("Private external (limited global scope), ");
  469.             if (symp->n_type & MAC_N_EXT ) printf ("External, ");
  470.             printf("%s", Lookup(MacSymbolTypeNames, symp->n_type & MAC_N_TYPE));
  471.          }
  472.          printf("\n    Reference type: %s,  Flags: ",
  473.             Lookup(MacSymbolReferenceTypeNames, symp->n_desc & MAC_REF_TYPE));
  474.          for (uint32 f = MAC_REFERENCED_DYNAMICALLY; f <= MAC_N_WEAK_DEF; f <<= 1) {
  475.             if (symp->n_desc & f) {
  476.                printf("%s, ", Lookup(MacSymbolDescriptorFlagNames, f));
  477.             }
  478.          }
  479.       }
  480.       // Check if indirect symbol table is valid
  481.       if (IndirectSymTabNumber && IndirectSymTabOffset + IndirectSymTabNumber*4 < this->GetDataSize()) {
  482.  
  483.          // Write indirect symbol table
  484.          printf("\n\n  Indirect symbols:");
  485.  
  486.          // loop through indirect symbol table
  487.          uint32 * IndSymip = (uint32*)(Buf() + IndirectSymTabOffset);
  488.  
  489.          for (i = 0; i < IndirectSymTabNumber; i++, IndSymip++) {
  490.  
  491.             // Check if index within symbol table
  492.             if (*IndSymip >= SymTabNumber) {
  493.                //err.submit(2016);
  494.                printf("\n   Unknown(0x%X)", *IndSymip);
  495.                continue;
  496.             }
  497.             // Find record
  498.             TMAC_nlist * pIndSym = symp0 + *IndSymip;
  499.             // Find name
  500.             uint32 StringIndex = pIndSym->n_strx;
  501.             if (StringIndex >= StringTabSize) {
  502.                err.submit(2035); continue;
  503.             }
  504.             // print name
  505.             printf("\n   %s", strtab + StringIndex);
  506.             // print type, etc.
  507.             printf(", type 0x%X, sect %i, desc 0x%X, val 0x%X",
  508.                pIndSym->n_type, pIndSym->n_sect, pIndSym->n_desc, uint32(pIndSym->n_value));
  509.          }
  510.       }
  511.    }
  512.  
  513.    // Dump string table
  514.    if (options & DUMP_STRINGTB) {
  515.       printf("\n\nString table:");
  516.       uint32 str = 0, istr = 0;
  517.       while (str < StringTabSize) {
  518.          char * p = (char*)(Buf() + StringTabOffset + str);
  519.          printf("\n  %3i: %s", str, p);
  520.          istr++;  str += (uint32)strlen(p) + 1;
  521.       }
  522.    }
  523.  
  524. }
  525.  
  526. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  527. void CMACHO<MACSTRUCTURES>::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
  528.    // Make list of public names
  529.    uint32 i;
  530.    SStringEntry se;                    // Entry in Index
  531.  
  532.    // Interpret header:
  533.    ParseFile();
  534.  
  535.    // pointer to string table
  536.    char * strtab = (char*)(Buf() + StringTabOffset);
  537.  
  538.    // loop through public symbol table
  539.    TMAC_nlist * symp = (TMAC_nlist*)(Buf() + SymTabOffset + iextdefsym * sizeof(TMAC_nlist));
  540.    for (i = 0; i < nextdefsym; i++, symp++) {
  541.       if (symp->n_strx < StringTabSize && !(symp->n_type & MAC_N_STAB)) {
  542.          // Public symbol found
  543.          se.Member = m;
  544.          // Store name
  545.          se.String = Strings->PushString(strtab + symp->n_strx);        
  546.          // Store name index
  547.          Index->Push(se);
  548.       }
  549.    }
  550. }
  551.  
  552. // Member functions for class MacSymbolTableBuilder
  553.  
  554. template <class TMAC_nlist, class MInt>
  555. MacSymbolTableBuilder<TMAC_nlist, MInt>::MacSymbolTableBuilder() {                       // Constructor
  556.    sorted = 0;
  557. }
  558.  
  559. template <class TMAC_nlist, class MInt>
  560. void MacSymbolTableBuilder<TMAC_nlist, MInt>::AddSymbol(int OldIndex, const char * name, int type, int Desc, int section, MInt value) {
  561.    // Add symbol to list
  562.    MacSymbolRecord<TMAC_nlist> rec;
  563.    memset(&rec, 0, sizeof(rec));                 // Set to zero
  564. /* !!
  565.    if (GetNumEntries() == 0) {
  566.       // First record must indicate empty string
  567.       rec.Name = StringBuffer.PushString("");    // Empty string
  568.       Push(&rec, sizeof(rec));                   // Put empty record in memory buffer
  569.    }
  570. */
  571.    rec.n_type = (uint8)type;                     // Copy values
  572.    rec.n_sect = (uint8)section;
  573.    rec.n_desc = (int16)Desc;
  574.    rec.n_value = value;
  575.    rec.Name = StringBuffer.PushString(name);     // Copy name and store index
  576.    rec.OldIndex = OldIndex;                      // Remember old index
  577.    Push(&rec, sizeof(rec));                      // Put in memory buffer
  578.    sorted = 0;                                   // Remember not sorted
  579. }
  580.  
  581. template <class TMAC_nlist, class MInt>
  582. void MacSymbolTableBuilder<TMAC_nlist, MInt>::SortList() {
  583.    // Sort the list
  584.    if (sorted) return; // allready sorted
  585.  
  586.    MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf();     // Point to list
  587.  
  588.    // Simple Shell sort with Sedgewick gaps:
  589.    int i, j, k, gap, n = (int)GetNumEntries();
  590.    for (k = 15; k >= 0; k--) {
  591.       gap = (1 << 2 * k) | (3 << k >> 1) | 1;   // Sedgewick gap grants O(N^4/3)
  592.       for (i = gap; i < n; i++) {
  593.          MacSymbolRecord<TMAC_nlist> key = p[i];
  594.          char * strkey = StringBuffer.Buf() + key.Name;
  595.          for (j = i - gap; j >= 0 && strcmp(strkey, StringBuffer.Buf() + p[j].Name) < 0; j -= gap) {
  596.             p[j + gap] = p[j];
  597.          }
  598.          p[j + gap] = key;
  599.       }
  600.    }
  601.  
  602.    sorted = 1;
  603. }
  604.  
  605. template <class TMAC_nlist, class MInt>
  606. int MacSymbolTableBuilder<TMAC_nlist, MInt>::TranslateIndex(int OldIndex) {
  607.    // Translate old index to new index (0-based)
  608.    // Returns -1 if not found
  609.  
  610.    // Don't sort list. This would change indices if __mh_executer_header added later
  611.    // if (!sorted) SortList();
  612.  
  613.    MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf();     // Point to list
  614.  
  615.    // Search through list for OldIndex
  616.    for (int i = 0; i < (int)GetNumEntries(); i++) {
  617.       if (p[i].OldIndex == OldIndex) {
  618.          // Match found
  619.          return i;
  620.       }
  621.    }
  622.    // Not found
  623.    return -1;
  624. }
  625.  
  626. template <class TMAC_nlist, class MInt>
  627. void MacSymbolTableBuilder<TMAC_nlist, MInt>::StoreList(CMemoryBuffer * SymbolTable, CMemoryBuffer * StringTable) {
  628.    // Store sorted list in buffers
  629.  
  630.    // Don't sort list unless commanded to do so. Will mess up indices
  631.    // if (!sorted) SortList();                           // Make sure list is sorted
  632.  
  633.    MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf();     // Point to list
  634.  
  635.    for (uint32 i = 0; i < GetNumEntries(); i++, p++) {
  636.       p->n_strx = StringTable->PushString(StringBuffer.Buf()+p->Name);   // Put name in string table
  637.       SymbolTable->Push(p, sizeof(TMAC_nlist));        // Store only the TMAC_nlist part of the record in SymbolTable
  638.    }
  639. }
  640.  
  641. template <class TMAC_nlist, class MInt>
  642. int MacSymbolTableBuilder<TMAC_nlist, MInt>::Search(const char * name) {
  643.    // Search for name. Return -1 if not found.
  644.    MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf();     // Point to list
  645.    for (int i = 0; i < (int)GetNumEntries(); i++) {
  646.       if (strcmp(StringBuffer.Buf()+p[i].Name, name) == 0) {
  647.          return i;  // Found
  648.       }
  649.    }
  650.    return -1;   // Not found
  651. }
  652.  
  653. template <class TMAC_nlist, class MInt>
  654. MacSymbolRecord<TMAC_nlist> & MacSymbolTableBuilder<TMAC_nlist, MInt>::operator[] (uint32 i) {
  655.    // Access member
  656.    uint32 Offset = i * sizeof(MacSymbolRecord<TMAC_nlist>);
  657.    if (i + sizeof(MacSymbolRecord<TMAC_nlist>) > this->GetDataSize()) {
  658.       err.submit(9003);  Offset = 0;
  659.    }
  660.    return Get<MacSymbolRecord<TMAC_nlist> >(Offset);
  661. }
  662.  
  663.  
  664. /****** Class CMACUNIV for parsing Macintosh universal binary *************/
  665. CMACUNIV::CMACUNIV() {
  666.    // Default constructor
  667. }
  668.  
  669.  
  670. void CMACUNIV::Go(int options) {
  671.    // Apply command options to all components
  672.  
  673.    // Check file size
  674.    if (GetDataSize() < 28) return;
  675.  
  676.    // Read number of components
  677.    uint32 NumComponents = EndianChange(Get<MAC_UNIV_FAT_HEADER>(0).num_arch);
  678.    if (NumComponents == 0 || NumComponents > 10) {
  679.       // Number of components too big or too small
  680.       err.submit(2701, NumComponents);
  681.       return;
  682.    }
  683.  
  684.    uint32 i;                                     // Component number
  685.    uint32 fo;                                    // File offset of component pointer
  686.    CConverter ComponentBuffer;                   // Used for converting component
  687.    CConverter OutputBuffer;                      // Temporary storage of output file
  688.    int DesiredWordSize = cmd.DesiredWordSize;    // Desired word size, if specified on command line
  689.  
  690.    // Loop through components
  691.    for (i = 0, fo = sizeof(MAC_UNIV_FAT_HEADER); i < NumComponents; i++, fo += sizeof(MAC_UNIV_FAT_ARCH)) {
  692.  
  693.       // Get component pointer
  694.       MAC_UNIV_FAT_ARCH & ComponentPointer = Get<MAC_UNIV_FAT_ARCH>(fo);
  695.  
  696.       // Get offset and size of component
  697.       uint32 ComponentOffset = EndianChange(ComponentPointer.offset);
  698.       uint32 ComponentSize   = EndianChange(ComponentPointer.size);
  699.  
  700.       // Check within range
  701.       if (ComponentOffset + ComponentSize > GetDataSize()) {
  702.          err.submit(2016);
  703.          return;
  704.       }
  705.  
  706.       // Put component into buffer
  707.       ComponentBuffer.Reset();
  708.       ComponentBuffer.Push(Buf() + ComponentOffset, ComponentSize);
  709.  
  710.       // Indicate component
  711.       printf("\n\n\nComponent file number %i:\n", i + 1);
  712.  
  713.       // Check type
  714.       uint32 ComponentType = ComponentBuffer.GetFileType();
  715.       if (DesiredWordSize && DesiredWordSize != ComponentBuffer.WordSize) {
  716.          err.submit(1151, ComponentBuffer.WordSize);
  717.       }
  718.       else if (ComponentType != FILETYPE_MACHO_LE) {
  719.          // Format not supported
  720.          printf("  Format not supported: %s", GetFileFormatName(ComponentType));
  721.       }
  722.       else {
  723.          // Format OK. Handle component
  724.          if (cmd.DumpOptions == 0 && OutputBuffer.GetDataSize()) {
  725.             // More than one component that can be converted
  726.             err.submit(1150);
  727.          }
  728.          else {
  729.             // Transfer filenames
  730.             ComponentBuffer.FileName = FileName;
  731.             ComponentBuffer.OutputFileName = OutputFileName;
  732.             // Do command
  733.             ComponentBuffer.Go();
  734.             // Is there an output file?
  735.             if (cmd.DumpOptions == 0) {
  736.                // Save output file
  737.                ComponentBuffer >> OutputBuffer;
  738.             }
  739.          }
  740.       }
  741.    }
  742.    // Is there an output file?
  743.    if (OutputBuffer.GetDataSize()) {
  744.       // Take over output file and skip remaining components
  745.       *this << OutputBuffer;
  746.    }
  747. }
  748.  
  749.  
  750. // Make template instances for 32 and 64 bits
  751. template class CMACHO<MAC32STRUCTURES>;
  752. template class CMACHO<MAC64STRUCTURES>;
  753. template class MacSymbolTableBuilder<MAC_nlist_32, int32>;
  754. template class MacSymbolTableBuilder<MAC_nlist_64, int64>;
  755.