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>
CMACHO()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>
ParseFile()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_t cmd, cmdsize;
142    uint32_t currentoffset = sizeof(TMAC_header);
143    for (uint32_t i = 1; i <= FileHeader.ncmds; i++) {
144       if (currentoffset >= this->GetDataSize()) {
145          err.submit(2016); return;
146       }
147       uint8_t * currentp = (uint8_t*)(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_t)sh->fileoff;      // File offset of segment
166             SegmentSize = (uint32_t)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>
Dump(int options)198 void CMACHO<MACSTRUCTURES>::Dump(int options) {
199    uint32_t icmd;                        // Command index
200    int32_t  isec1;                       // Section index within segment
201    int32_t  isec2;                       // Section index global
202    int32_t  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_t cmd;                         // Load command
222    uint32_t cmdsize;                     // Command size
223    // Pointer to current position
224    uint8_t * currentp = (uint8_t*)(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_t)(sh->vmaddr>>32), (uint32_t)sh->vmaddr,
254                   (uint32_t)(sh->vmsize>>32), (uint32_t)sh->vmsize,
255                   (uint32_t)(sh->fileoff>>32), (uint32_t)sh->fileoff,
256                   (uint32_t)(sh->filesize>>32), (uint32_t)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_t*)(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_t 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_t*)(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_t*)(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_t)sectp->addr, (uint32_t)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_t 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_t*)(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_t*)(Buf()+sectp->offset+relp->r_address+4), *(int32_t*)(Buf()+sectp->offset+relp->r_address));
421                            }
422                            else {
423                               // 4 bytes inline addend
424                               printf(", Inline: 0x%08X", *(int32_t*)(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_t 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_t(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_t(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_t 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_t * IndSymip = (uint32_t*)(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_t 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_t(pIndSym->n_value));
509          }
510       }
511    }
512 
513    // Dump string table
514    if (options & DUMP_STRINGTB) {
515       printf("\n\nString table:");
516       uint32_t 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_t)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>
PublicNames(CMemoryBuffer * Strings,CSList<SStringEntry> * Index,int m)527 void CMACHO<MACSTRUCTURES>::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
528    // Make list of public names
529    uint32_t 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>
MacSymbolTableBuilder()555 MacSymbolTableBuilder<TMAC_nlist, MInt>::MacSymbolTableBuilder() {                       // Constructor
556    sorted = 0;
557 }
558 
559 template <class TMAC_nlist, class MInt>
AddSymbol(int OldIndex,const char * name,int type,int Desc,int section,MInt value)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_t)type;                     // Copy values
572    rec.n_sect = (uint8_t)section;
573    rec.n_desc = (int16_t)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>
SortList()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 Bubble sort:
589    int i, j;  const char * s1, * s2;
590    MacSymbolRecord<TMAC_nlist> temp;
591    for (i = 0; i < (int)GetNumEntries(); i++) {
592       for (j = 0; j < (int)GetNumEntries() - i - 1; j++) {
593          s1 = (char*)StringBuffer.Buf() + p[j].Name;
594          s2 = (char*)StringBuffer.Buf() + p[j+1].Name;
595          if (strcmp(s1, s2) > 0) {
596             // Swap records
597             temp = p[j];
598             p[j] = p[j+1];
599             p[j+1] = temp;
600          }
601       }
602    }
603    sorted = 1;
604 }
605 
606 template <class TMAC_nlist, class MInt>
TranslateIndex(int OldIndex)607 int MacSymbolTableBuilder<TMAC_nlist, MInt>::TranslateIndex(int OldIndex) {
608    // Translate old index to new index (0-based)
609    // Returns -1 if not found
610 
611    // Don't sort list. This would change indices if __mh_executer_header added later
612    // if (!sorted) SortList();
613 
614    MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf();     // Point to list
615 
616    // Search through list for OldIndex
617    for (int i = 0; i < (int)GetNumEntries(); i++) {
618       if (p[i].OldIndex == OldIndex) {
619          // Match found
620          return i;
621       }
622    }
623    // Not found
624    return -1;
625 }
626 
627 template <class TMAC_nlist, class MInt>
StoreList(CMemoryBuffer * SymbolTable,CMemoryBuffer * StringTable)628 void MacSymbolTableBuilder<TMAC_nlist, MInt>::StoreList(CMemoryBuffer * SymbolTable, CMemoryBuffer * StringTable) {
629    // Store sorted list in buffers
630 
631    // Don't sort list unless commanded to do so. Will mess up indices
632    // if (!sorted) SortList();                           // Make sure list is sorted
633 
634    MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf();     // Point to list
635 
636    for (uint32_t i = 0; i < GetNumEntries(); i++, p++) {
637       p->n_strx = StringTable->PushString((char*)StringBuffer.Buf()+p->Name);   // Put name in string table
638       SymbolTable->Push(p, sizeof(TMAC_nlist));        // Store only the TMAC_nlist part of the record in SymbolTable
639    }
640 }
641 
642 template <class TMAC_nlist, class MInt>
Search(const char * name)643 int MacSymbolTableBuilder<TMAC_nlist, MInt>::Search(const char * name) {
644    // Search for name. Return -1 if not found.
645    MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf();     // Point to list
646    for (int i = 0; i < (int)GetNumEntries(); i++) {
647       if (strcmp((char*)StringBuffer.Buf()+p[i].Name, name) == 0) {
648          return i;  // Found
649       }
650    }
651    return -1;   // Not found
652 }
653 
654 template <class TMAC_nlist, class MInt>
operator [](uint32_t i)655 MacSymbolRecord<TMAC_nlist> & MacSymbolTableBuilder<TMAC_nlist, MInt>::operator[] (uint32_t i) {
656    // Access member
657    uint32_t Offset = i * sizeof(MacSymbolRecord<TMAC_nlist>);
658    if (i + sizeof(MacSymbolRecord<TMAC_nlist>) > this->GetDataSize()) {
659       err.submit(9003);  Offset = 0;
660    }
661    return Get<MacSymbolRecord<TMAC_nlist> >(Offset);
662 }
663 
664 
665 /****** Class CMACUNIV for parsing Macintosh universal binary *************/
CMACUNIV()666 CMACUNIV::CMACUNIV() {
667    // Default constructor
668 }
669 
670 
Go(int options)671 void CMACUNIV::Go(int options) {
672    // Apply command options to all components
673 
674    // Check file size
675    if (GetDataSize() < 28) return;
676 
677    // Read number of components
678    uint32_t NumComponents = EndianChange(Get<MAC_UNIV_FAT_HEADER>(0).num_arch);
679    if (NumComponents == 0 || NumComponents > 10) {
680       // Number of components too big or too small
681       err.submit(2701, NumComponents);
682       return;
683    }
684 
685    uint32_t i;                                     // Component number
686    uint32_t fo;                                    // File offset of component pointer
687    CConverter ComponentBuffer;                   // Used for converting component
688    CConverter OutputBuffer;                      // Temporary storage of output file
689    int DesiredWordSize = cmd.DesiredWordSize;    // Desired word size, if specified on command line
690 
691    // Loop through components
692    for (i = 0, fo = sizeof(MAC_UNIV_FAT_HEADER); i < NumComponents; i++, fo += sizeof(MAC_UNIV_FAT_ARCH)) {
693 
694       // Get component pointer
695       MAC_UNIV_FAT_ARCH & ComponentPointer = Get<MAC_UNIV_FAT_ARCH>(fo);
696 
697       // Get offset and size of component
698       uint32_t ComponentOffset = EndianChange(ComponentPointer.offset);
699       uint32_t ComponentSize   = EndianChange(ComponentPointer.size);
700 
701       // Check within range
702       if (ComponentOffset + ComponentSize > GetDataSize()) {
703          err.submit(2016);
704          return;
705       }
706 
707       // Put component into buffer
708       ComponentBuffer.Reset();
709       ComponentBuffer.Push(Buf() + ComponentOffset, ComponentSize);
710 
711       // Indicate component
712       printf("\n\n\nComponent file number %i:\n", i + 1);
713 
714       // Check type
715       uint32_t ComponentType = ComponentBuffer.GetFileType();
716       if (DesiredWordSize && DesiredWordSize != ComponentBuffer.WordSize) {
717          err.submit(1151, ComponentBuffer.WordSize);
718       }
719       else if (ComponentType != FILETYPE_MACHO_LE) {
720          // Format not supported
721          printf("  Format not supported: %s", GetFileFormatName(ComponentType));
722       }
723       else {
724          // Format OK. Handle component
725          if (cmd.DumpOptions == 0 && OutputBuffer.GetDataSize()) {
726             // More than one component that can be converted
727             err.submit(1150);
728          }
729          else {
730             // Transfer filenames
731             ComponentBuffer.FileName = FileName;
732             ComponentBuffer.OutputFileName = OutputFileName;
733             // Do command
734             ComponentBuffer.Go();
735             // Is there an output file?
736             if (cmd.DumpOptions == 0) {
737                // Save output file
738                ComponentBuffer >> OutputBuffer;
739             }
740          }
741       }
742    }
743    // Is there an output file?
744    if (OutputBuffer.GetDataSize()) {
745       // Take over output file and skip remaining components
746       *this << OutputBuffer;
747    }
748 }
749 
750 
751 // Make template instances for 32 and 64 bits
752 template class CMACHO<MAC32STRUCTURES>;
753 template class CMACHO<MAC64STRUCTURES>;
754 template class MacSymbolTableBuilder<MAC_nlist_32, int32_t>;
755 template class MacSymbolTableBuilder<MAC_nlist_64, int64_t>;
756