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