]> git.saurik.com Git - apple/ld64.git/blob - src/other/dyldinfo.cpp
5c4247139bacba654084ee19da8b7e943345c88c
[apple/ld64.git] / src / other / dyldinfo.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <errno.h>
33
34 #include <vector>
35 #include <set>
36 #include <ext/hash_set>
37
38 #include "MachOFileAbstraction.hpp"
39 #include "Architectures.hpp"
40 #include "MachOTrie.hpp"
41
42 static bool printRebase = false;
43 static bool printBind = false;
44 static bool printWeakBind = false;
45 static bool printLazyBind = false;
46 static bool printOpcodes = false;
47 static bool printExport = false;
48 static bool printExportGraph = false;
49 static cpu_type_t sPreferredArch = CPU_TYPE_I386;
50 static cpu_type_t sPreferredSubArch = 0;
51
52
53 __attribute__((noreturn))
54 void throwf(const char* format, ...)
55 {
56 va_list list;
57 char* p;
58 va_start(list, format);
59 vasprintf(&p, format, list);
60 va_end(list);
61
62 const char* t = p;
63 throw t;
64 }
65
66
67 template <typename A>
68 class DyldInfoPrinter
69 {
70 public:
71 static bool validFile(const uint8_t* fileContent);
72 static DyldInfoPrinter<A>* make(const uint8_t* fileContent, uint32_t fileLength, const char* path)
73 { return new DyldInfoPrinter<A>(fileContent, fileLength, path); }
74 virtual ~DyldInfoPrinter() {}
75
76
77 private:
78 typedef typename A::P P;
79 typedef typename A::P::E E;
80 typedef typename A::P::uint_t pint_t;
81
82 class CStringEquals
83 {
84 public:
85 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
86 };
87
88 typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringSet;
89
90 DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path);
91 void printRebaseInfo();
92 void printRebaseInfoOpcodes();
93 void printBindingInfo();
94 void printWeakBindingInfo();
95 void printLazyBindingInfo();
96 void printBindingInfoOpcodes(bool weakBinding);
97 void printWeakBindingInfoOpcodes();
98 void printLazyBindingOpcodes();
99 void printExportInfo();
100 void printExportInfoGraph();
101 void printRelocRebaseInfo();
102 void printSymbolTableExportInfo();
103 void printClassicLazyBindingInfo();
104 void printClassicBindingInfo();
105 pint_t relocBase();
106 const char* relocTypeName(uint8_t r_type);
107 uint8_t segmentIndexForAddress(pint_t addr);
108 void processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end,
109 char* cummulativeString, int curStrOffset);
110 void processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
111 const uint8_t* parent, const uint8_t* p,
112 char* cummulativeString, int curStrOffset);
113 const char* rebaseTypeName(uint8_t type);
114 const char* bindTypeName(uint8_t type);
115 pint_t segStartAddress(uint8_t segIndex);
116 const char* segmentName(uint8_t segIndex);
117 const char* sectionName(uint8_t segIndex, pint_t address);
118 const char* getSegAndSectName(uint8_t segIndex, pint_t address);
119 const char* ordinalName(int libraryOrdinal);
120 const char* classicOrdinalName(int libraryOrdinal);
121 pint_t* mappedAddressForVMAddress(pint_t vmaddress);
122
123
124
125 const char* fPath;
126 const macho_header<P>* fHeader;
127 uint64_t fLength;
128 const char* fStrings;
129 const char* fStringsEnd;
130 const macho_nlist<P>* fSymbols;
131 uint32_t fSymbolCount;
132 const macho_dyld_info_command<P>* fInfo;
133 uint64_t fBaseAddress;
134 const macho_dysymtab_command<P>* fDynamicSymbolTable;
135 const macho_segment_command<P>* fFirstSegment;
136 const macho_segment_command<P>* fFirstWritableSegment;
137 bool fWriteableSegmentWithAddrOver4G;
138 std::vector<const macho_segment_command<P>*>fSegments;
139 std::vector<const char*> fDylibs;
140 };
141
142
143
144 template <>
145 bool DyldInfoPrinter<ppc>::validFile(const uint8_t* fileContent)
146 {
147 const macho_header<P>* header = (const macho_header<P>*)fileContent;
148 if ( header->magic() != MH_MAGIC )
149 return false;
150 if ( header->cputype() != CPU_TYPE_POWERPC )
151 return false;
152 switch (header->filetype()) {
153 case MH_EXECUTE:
154 case MH_DYLIB:
155 case MH_BUNDLE:
156 case MH_DYLINKER:
157 return true;
158 }
159 return false;
160 }
161
162 template <>
163 bool DyldInfoPrinter<ppc64>::validFile(const uint8_t* fileContent)
164 {
165 const macho_header<P>* header = (const macho_header<P>*)fileContent;
166 if ( header->magic() != MH_MAGIC_64 )
167 return false;
168 if ( header->cputype() != CPU_TYPE_POWERPC64 )
169 return false;
170 switch (header->filetype()) {
171 case MH_EXECUTE:
172 case MH_DYLIB:
173 case MH_BUNDLE:
174 case MH_DYLINKER:
175 return true;
176 }
177 return false;
178 }
179
180 template <>
181 bool DyldInfoPrinter<x86>::validFile(const uint8_t* fileContent)
182 {
183 const macho_header<P>* header = (const macho_header<P>*)fileContent;
184 if ( header->magic() != MH_MAGIC )
185 return false;
186 if ( header->cputype() != CPU_TYPE_I386 )
187 return false;
188 switch (header->filetype()) {
189 case MH_EXECUTE:
190 case MH_DYLIB:
191 case MH_BUNDLE:
192 case MH_DYLINKER:
193 return true;
194 }
195 return false;
196 }
197
198 template <>
199 bool DyldInfoPrinter<x86_64>::validFile(const uint8_t* fileContent)
200 {
201 const macho_header<P>* header = (const macho_header<P>*)fileContent;
202 if ( header->magic() != MH_MAGIC_64 )
203 return false;
204 if ( header->cputype() != CPU_TYPE_X86_64 )
205 return false;
206 switch (header->filetype()) {
207 case MH_EXECUTE:
208 case MH_DYLIB:
209 case MH_BUNDLE:
210 case MH_DYLINKER:
211 return true;
212 }
213 return false;
214 }
215
216 template <>
217 bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
218 {
219 const macho_header<P>* header = (const macho_header<P>*)fileContent;
220 if ( header->magic() != MH_MAGIC )
221 return false;
222 if ( header->cputype() != CPU_TYPE_ARM )
223 return false;
224 switch (header->filetype()) {
225 case MH_EXECUTE:
226 case MH_DYLIB:
227 case MH_BUNDLE:
228 case MH_DYLINKER:
229 return true;
230 }
231 return false;
232 }
233
234 template <typename A>
235 DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path)
236 : fHeader(NULL), fLength(fileLength),
237 fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL),
238 fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL),
239 fWriteableSegmentWithAddrOver4G(false)
240 {
241 // sanity check
242 if ( ! validFile(fileContent) )
243 throw "not a mach-o file that can be checked";
244
245 fPath = strdup(path);
246 fHeader = (const macho_header<P>*)fileContent;
247
248 // get LC_DYLD_INFO
249 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
250 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
251 const uint32_t cmd_count = fHeader->ncmds();
252 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
253 const macho_load_command<P>* cmd = cmds;
254 for (uint32_t i = 0; i < cmd_count; ++i) {
255 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
256 if ( endOfCmd > endOfLoadCommands )
257 throwf("load command #%d extends beyond the end of the load commands", i);
258 if ( endOfCmd > endOfFile )
259 throwf("load command #%d extends beyond the end of the file", i);
260 switch ( cmd->cmd() ) {
261 case LC_DYLD_INFO:
262 case LC_DYLD_INFO_ONLY:
263 fInfo = (macho_dyld_info_command<P>*)cmd;
264 break;
265 case macho_segment_command<P>::CMD:
266 {
267 const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
268 fSegments.push_back(segCmd);
269 if ( (segCmd->fileoff() == 0) && (segCmd->filesize() != 0) )
270 fBaseAddress = segCmd->vmaddr();
271 if ( fFirstSegment == NULL )
272 fFirstSegment = segCmd;
273 if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) {
274 if ( fFirstWritableSegment == NULL )
275 fFirstWritableSegment = segCmd;
276 if ( segCmd->vmaddr() > 0x100000000ULL )
277 fWriteableSegmentWithAddrOver4G = true;
278 }
279 }
280 break;
281 case LC_LOAD_DYLIB:
282 case LC_LOAD_WEAK_DYLIB:
283 case LC_REEXPORT_DYLIB:
284 case LC_LAZY_LOAD_DYLIB:
285 {
286 const macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
287 const char* lastSlash = strrchr(dylib->name(), '/');
288 const char* leafName = (lastSlash != NULL) ? lastSlash+1 : dylib->name();
289 const char* firstDot = strchr(leafName, '.');
290 if ( firstDot != NULL ) {
291 char* t = strdup(leafName);
292 t[firstDot-leafName] = '\0';
293 fDylibs.push_back(t);
294 }
295 else {
296 fDylibs.push_back(leafName);
297 }
298 }
299 break;
300 case LC_DYSYMTAB:
301 fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
302 break;
303 case LC_SYMTAB:
304 {
305 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
306 fSymbolCount = symtab->nsyms();
307 fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
308 fStrings = (char*)fHeader + symtab->stroff();
309 fStringsEnd = fStrings + symtab->strsize();
310 }
311 break;
312 }
313 cmd = (const macho_load_command<P>*)endOfCmd;
314 }
315
316 if ( printRebase ) {
317 if ( fInfo != NULL )
318 printRebaseInfo();
319 else
320 printRelocRebaseInfo();
321 }
322 if ( printBind ) {
323 if ( fInfo != NULL )
324 printBindingInfo();
325 else
326 printClassicBindingInfo();
327 }
328 if ( printWeakBind )
329 printWeakBindingInfo();
330 if ( printLazyBind ) {
331 if ( fInfo != NULL )
332 printLazyBindingInfo();
333 else
334 printClassicLazyBindingInfo();
335 }
336 if ( printExport ) {
337 if ( fInfo != NULL )
338 printExportInfo();
339 else
340 printSymbolTableExportInfo();
341 }
342 if ( printOpcodes ) {
343 printRebaseInfoOpcodes();
344 printBindingInfoOpcodes(false);
345 printBindingInfoOpcodes(true);
346 printLazyBindingOpcodes();
347 }
348 if ( printExportGraph )
349 printExportInfoGraph();
350 }
351
352 static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
353 {
354 uint64_t result = 0;
355 int bit = 0;
356 do {
357 if (p == end)
358 throwf("malformed uleb128");
359
360 uint64_t slice = *p & 0x7f;
361
362 if (bit >= 64 || slice << bit >> bit != slice)
363 throwf("uleb128 too big");
364 else {
365 result |= (slice << bit);
366 bit += 7;
367 }
368 }
369 while (*p++ & 0x80);
370 return result;
371 }
372
373 static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
374 {
375 int64_t result = 0;
376 int bit = 0;
377 uint8_t byte;
378 do {
379 if (p == end)
380 throwf("malformed sleb128");
381 byte = *p++;
382 result |= ((byte & 0x7f) << bit);
383 bit += 7;
384 } while (byte & 0x80);
385 // sign extend negative numbers
386 if ( (byte & 0x40) != 0 )
387 result |= (-1LL) << bit;
388 return result;
389 }
390
391
392 template <typename A>
393 const char* DyldInfoPrinter<A>::rebaseTypeName(uint8_t type)
394 {
395 switch (type ){
396 case REBASE_TYPE_POINTER:
397 return "pointer";
398 case REBASE_TYPE_TEXT_ABSOLUTE32:
399 return "text abs32";
400 case REBASE_TYPE_TEXT_PCREL32:
401 return "text rel32";
402 }
403 return "!!unknown!!";
404 }
405
406
407 template <typename A>
408 const char* DyldInfoPrinter<A>::bindTypeName(uint8_t type)
409 {
410 switch (type ){
411 case BIND_TYPE_POINTER:
412 return "pointer";
413 case BIND_TYPE_TEXT_ABSOLUTE32:
414 return "text abs32";
415 case BIND_TYPE_TEXT_PCREL32:
416 return "text rel32";
417 }
418 return "!!unknown!!";
419 }
420
421
422 template <typename A>
423 typename A::P::uint_t DyldInfoPrinter<A>::segStartAddress(uint8_t segIndex)
424 {
425 if ( segIndex > fSegments.size() )
426 throw "segment index out of range";
427 return fSegments[segIndex]->vmaddr();
428 }
429
430 template <typename A>
431 const char* DyldInfoPrinter<A>::segmentName(uint8_t segIndex)
432 {
433 if ( segIndex > fSegments.size() )
434 throw "segment index out of range";
435 return fSegments[segIndex]->segname();
436 }
437
438 template <typename A>
439 const char* DyldInfoPrinter<A>::sectionName(uint8_t segIndex, pint_t address)
440 {
441 if ( segIndex > fSegments.size() )
442 throw "segment index out of range";
443 const macho_segment_command<P>* segCmd = fSegments[segIndex];
444 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
445 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
446 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
447 if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
448 if ( strlen(sect->sectname()) > 15 ) {
449 static char temp[18];
450 strlcpy(temp, sect->sectname(), 17);
451 return temp;
452 }
453 else {
454 return sect->sectname();
455 }
456 }
457 }
458 return "??";
459 }
460
461 template <typename A>
462 const char* DyldInfoPrinter<A>::getSegAndSectName(uint8_t segIndex, pint_t address)
463 {
464 static char buffer[64];
465 strcpy(buffer, segmentName(segIndex));
466 strcat(buffer, "/");
467 const macho_segment_command<P>* segCmd = fSegments[segIndex];
468 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
469 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
470 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
471 if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
472 // section name may not be zero terminated
473 char* end = &buffer[strlen(buffer)];
474 strlcpy(end, sect->sectname(), 16);
475 return buffer;
476 }
477 }
478 return "??";
479 }
480
481 template <typename A>
482 uint8_t DyldInfoPrinter<A>::segmentIndexForAddress(pint_t address)
483 {
484 for(unsigned int i=0; i < fSegments.size(); ++i) {
485 if ( (fSegments[i]->vmaddr() <= address) && (address < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) {
486 return i;
487 }
488 }
489 throwf("address 0x%llX is not in any segment", (uint64_t)address);
490 }
491
492 template <typename A>
493 typename A::P::uint_t* DyldInfoPrinter<A>::mappedAddressForVMAddress(pint_t vmaddress)
494 {
495 for(unsigned int i=0; i < fSegments.size(); ++i) {
496 if ( (fSegments[i]->vmaddr() <= vmaddress) && (vmaddress < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) {
497 unsigned long offsetInMappedFile = fSegments[i]->fileoff()+vmaddress-fSegments[i]->vmaddr();
498 return (pint_t*)((uint8_t*)fHeader + offsetInMappedFile);
499 }
500 }
501 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress);
502 }
503
504 template <typename A>
505 const char* DyldInfoPrinter<A>::ordinalName(int libraryOrdinal)
506 {
507 switch ( libraryOrdinal) {
508 case BIND_SPECIAL_DYLIB_SELF:
509 return "this-image";
510 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
511 return "main-executable";
512 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
513 return "flat-namespace";
514 }
515 if ( libraryOrdinal < BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
516 throw "unknown special ordinal";
517 if ( libraryOrdinal > (int)fDylibs.size() )
518 throw "libraryOrdinal out of range";
519 return fDylibs[libraryOrdinal-1];
520 }
521
522 template <typename A>
523 const char* DyldInfoPrinter<A>::classicOrdinalName(int libraryOrdinal)
524 {
525 switch ( libraryOrdinal) {
526 case SELF_LIBRARY_ORDINAL:
527 return "this-image";
528 case EXECUTABLE_ORDINAL:
529 return "main-executable";
530 case DYNAMIC_LOOKUP_ORDINAL:
531 return "flat-namespace";
532 }
533 if ( libraryOrdinal > (int)fDylibs.size() )
534 throw "libraryOrdinal out of range";
535 return fDylibs[libraryOrdinal-1];
536 }
537
538 template <typename A>
539 void DyldInfoPrinter<A>::printRebaseInfo()
540 {
541 if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
542 printf("no compressed rebase info\n");
543 }
544 else {
545 printf("rebase information (from compressed dyld info):\n");
546 printf("segment section address type\n");
547
548 const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
549 const uint8_t* end = &p[fInfo->rebase_size()];
550
551 uint8_t type = 0;
552 uint64_t segOffset = 0;
553 uint32_t count;
554 uint32_t skip;
555 int segIndex;
556 pint_t segStartAddr = 0;
557 const char* segName = "??";
558 const char* typeName = "??";
559 bool done = false;
560 while ( !done && (p < end) ) {
561 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
562 uint8_t opcode = *p & REBASE_OPCODE_MASK;
563 ++p;
564 switch (opcode) {
565 case REBASE_OPCODE_DONE:
566 done = true;
567 break;
568 case REBASE_OPCODE_SET_TYPE_IMM:
569 type = immediate;
570 typeName = rebaseTypeName(type);
571 break;
572 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
573 segIndex = immediate;
574 segStartAddr = segStartAddress(segIndex);
575 segName = segmentName(segIndex);
576 segOffset = read_uleb128(p, end);
577 break;
578 case REBASE_OPCODE_ADD_ADDR_ULEB:
579 segOffset += read_uleb128(p, end);
580 break;
581 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
582 segOffset += immediate*sizeof(pint_t);
583 break;
584 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
585 for (int i=0; i < immediate; ++i) {
586 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
587 segOffset += sizeof(pint_t);
588 }
589 break;
590 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
591 count = read_uleb128(p, end);
592 for (uint32_t i=0; i < count; ++i) {
593 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
594 segOffset += sizeof(pint_t);
595 }
596 break;
597 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
598 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
599 segOffset += read_uleb128(p, end) + sizeof(pint_t);
600 break;
601 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
602 count = read_uleb128(p, end);
603 skip = read_uleb128(p, end);
604 for (uint32_t i=0; i < count; ++i) {
605 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
606 segOffset += skip + sizeof(pint_t);
607 }
608 break;
609 default:
610 throwf("bad rebase opcode %d", *p);
611 }
612 }
613 }
614
615 }
616
617
618
619 template <typename A>
620 void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
621 {
622 if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
623 printf("no compressed rebase info\n");
624 }
625 else {
626 printf("rebase opcodes:\n");
627 const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
628 const uint8_t* end = &p[fInfo->rebase_size()];
629
630 uint8_t type = 0;
631 uint64_t address = fBaseAddress;
632 uint32_t count;
633 uint32_t skip;
634 unsigned int segmentIndex;
635 bool done = false;
636 while ( !done && (p < end) ) {
637 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
638 uint8_t opcode = *p & REBASE_OPCODE_MASK;
639 ++p;
640 switch (opcode) {
641 case REBASE_OPCODE_DONE:
642 done = true;
643 printf("REBASE_OPCODE_DONE()\n");
644 break;
645 case REBASE_OPCODE_SET_TYPE_IMM:
646 type = immediate;
647 printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type);
648 break;
649 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
650 segmentIndex = immediate;
651 address = read_uleb128(p, end);
652 printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex, address);
653 break;
654 case REBASE_OPCODE_ADD_ADDR_ULEB:
655 address = read_uleb128(p, end);
656 printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address);
657 break;
658 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
659 address = immediate*sizeof(pint_t);
660 printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address);
661 break;
662 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
663 printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate);
664 break;
665 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
666 count = read_uleb128(p, end);
667 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count);
668 break;
669 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
670 skip = read_uleb128(p, end) + sizeof(pint_t);
671 printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip);
672 break;
673 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
674 count = read_uleb128(p, end);
675 skip = read_uleb128(p, end);
676 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count, skip);
677 break;
678 default:
679 throwf("bad rebase opcode %d", *p);
680 }
681 }
682 }
683
684 }
685
686
687
688
689
690
691 template <typename A>
692 void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
693 {
694 if ( fInfo == NULL ) {
695 printf("no compressed binding info\n");
696 }
697 else if ( !weakbinding && (fInfo->bind_off() == 0) ) {
698 printf("no compressed binding info\n");
699 }
700 else if ( weakbinding && (fInfo->weak_bind_off() == 0) ) {
701 printf("no compressed weak binding info\n");
702 }
703 else {
704 const uint8_t* start;
705 const uint8_t* end;
706 if ( weakbinding ) {
707 printf("weak binding opcodes:\n");
708 start = (uint8_t*)fHeader + fInfo->weak_bind_off();
709 end = &start[fInfo->weak_bind_size()];
710 }
711 else {
712 printf("binding opcodes:\n");
713 start = (uint8_t*)fHeader + fInfo->bind_off();
714 end = &start[fInfo->bind_size()];
715 }
716 const uint8_t* p = start;
717 uint8_t type = 0;
718 uint8_t flags;
719 uint64_t address = fBaseAddress;
720 const char* symbolName = NULL;
721 int libraryOrdinal = 0;
722 int64_t addend = 0;
723 uint32_t segmentIndex = 0;
724 uint32_t count;
725 uint32_t skip;
726 bool done = false;
727 while ( !done && (p < end) ) {
728 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
729 uint8_t opcode = *p & BIND_OPCODE_MASK;
730 uint32_t opcodeOffset = p-start;
731 ++p;
732 switch (opcode) {
733 case BIND_OPCODE_DONE:
734 done = true;
735 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
736 break;
737 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
738 libraryOrdinal = immediate;
739 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
740 break;
741 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
742 libraryOrdinal = read_uleb128(p, end);
743 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
744 break;
745 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
746 // the special ordinals are negative numbers
747 if ( immediate == 0 )
748 libraryOrdinal = 0;
749 else {
750 int8_t signExtended = BIND_OPCODE_MASK | immediate;
751 libraryOrdinal = signExtended;
752 }
753 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
754 break;
755 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
756 flags = immediate;
757 symbolName = (char*)p;
758 while (*p != '\0')
759 ++p;
760 ++p;
761 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
762 break;
763 case BIND_OPCODE_SET_TYPE_IMM:
764 type = immediate;
765 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
766 break;
767 case BIND_OPCODE_SET_ADDEND_SLEB:
768 addend = read_sleb128(p, end);
769 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
770 break;
771 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
772 segmentIndex = immediate;
773 address = read_uleb128(p, end);
774 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
775 break;
776 case BIND_OPCODE_ADD_ADDR_ULEB:
777 skip = read_uleb128(p, end);
778 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
779 break;
780 case BIND_OPCODE_DO_BIND:
781 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
782 break;
783 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
784 skip = read_uleb128(p, end);
785 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
786 break;
787 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
788 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
789 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
790 break;
791 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
792 count = read_uleb128(p, end);
793 skip = read_uleb128(p, end);
794 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
795 break;
796 default:
797 throwf("unknown bind opcode %d", *p);
798 }
799 }
800 }
801
802 }
803
804
805
806 template <typename A>
807 void DyldInfoPrinter<A>::printBindingInfo()
808 {
809 if ( (fInfo == NULL) || (fInfo->bind_off() == 0) ) {
810 printf("no compressed binding info\n");
811 }
812 else {
813 printf("bind information:\n");
814 printf("segment section address type weak addend dylib symbol\n");
815 const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
816 const uint8_t* end = &p[fInfo->bind_size()];
817
818 uint8_t type = 0;
819 uint8_t segIndex = 0;
820 uint64_t segOffset = 0;
821 const char* symbolName = NULL;
822 const char* fromDylib = "??";
823 int libraryOrdinal = 0;
824 int64_t addend = 0;
825 uint32_t count;
826 uint32_t skip;
827 pint_t segStartAddr = 0;
828 const char* segName = "??";
829 const char* typeName = "??";
830 const char* weak_import = "";
831 bool done = false;
832 while ( !done && (p < end) ) {
833 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
834 uint8_t opcode = *p & BIND_OPCODE_MASK;
835 ++p;
836 switch (opcode) {
837 case BIND_OPCODE_DONE:
838 done = true;
839 break;
840 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
841 libraryOrdinal = immediate;
842 fromDylib = ordinalName(libraryOrdinal);
843 break;
844 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
845 libraryOrdinal = read_uleb128(p, end);
846 fromDylib = ordinalName(libraryOrdinal);
847 break;
848 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
849 // the special ordinals are negative numbers
850 if ( immediate == 0 )
851 libraryOrdinal = 0;
852 else {
853 int8_t signExtended = BIND_OPCODE_MASK | immediate;
854 libraryOrdinal = signExtended;
855 }
856 fromDylib = ordinalName(libraryOrdinal);
857 break;
858 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
859 symbolName = (char*)p;
860 while (*p != '\0')
861 ++p;
862 ++p;
863 if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
864 weak_import = "weak";
865 else
866 weak_import = "";
867 break;
868 case BIND_OPCODE_SET_TYPE_IMM:
869 type = immediate;
870 typeName = bindTypeName(type);
871 break;
872 case BIND_OPCODE_SET_ADDEND_SLEB:
873 addend = read_sleb128(p, end);
874 break;
875 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
876 segIndex = immediate;
877 segStartAddr = segStartAddress(segIndex);
878 segName = segmentName(segIndex);
879 segOffset = read_uleb128(p, end);
880 break;
881 case BIND_OPCODE_ADD_ADDR_ULEB:
882 segOffset += read_uleb128(p, end);
883 break;
884 case BIND_OPCODE_DO_BIND:
885 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
886 segOffset += sizeof(pint_t);
887 break;
888 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
889 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
890 segOffset += read_uleb128(p, end) + sizeof(pint_t);
891 break;
892 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
893 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
894 segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
895 break;
896 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
897 count = read_uleb128(p, end);
898 skip = read_uleb128(p, end);
899 for (uint32_t i=0; i < count; ++i) {
900 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
901 segOffset += skip + sizeof(pint_t);
902 }
903 break;
904 default:
905 throwf("bad bind opcode %d", *p);
906 }
907 }
908 }
909
910 }
911
912 template <typename A>
913 void DyldInfoPrinter<A>::printWeakBindingInfo()
914 {
915 if ( (fInfo == NULL) || (fInfo->weak_bind_off() == 0) ) {
916 printf("no weak binding\n");
917 }
918 else {
919 printf("weak binding information:\n");
920 printf("segment section address type addend symbol\n");
921 const uint8_t* p = (uint8_t*)fHeader + fInfo->weak_bind_off();
922 const uint8_t* end = &p[fInfo->weak_bind_size()];
923
924 uint8_t type = 0;
925 uint8_t segIndex = 0;
926 uint64_t segOffset = 0;
927 const char* symbolName = NULL;
928 int64_t addend = 0;
929 uint32_t count;
930 uint32_t skip;
931 pint_t segStartAddr = 0;
932 const char* segName = "??";
933 const char* typeName = "??";
934 bool done = false;
935 while ( !done && (p < end) ) {
936 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
937 uint8_t opcode = *p & BIND_OPCODE_MASK;
938 ++p;
939 switch (opcode) {
940 case BIND_OPCODE_DONE:
941 done = true;
942 break;
943 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
944 symbolName = (char*)p;
945 while (*p != '\0')
946 ++p;
947 ++p;
948 if ( (immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) != 0 )
949 printf(" strong %s\n", symbolName );
950 break;
951 case BIND_OPCODE_SET_TYPE_IMM:
952 type = immediate;
953 typeName = bindTypeName(type);
954 break;
955 case BIND_OPCODE_SET_ADDEND_SLEB:
956 addend = read_sleb128(p, end);
957 break;
958 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
959 segIndex = immediate;
960 segStartAddr = segStartAddress(segIndex);
961 segName = segmentName(segIndex);
962 segOffset = read_uleb128(p, end);
963 break;
964 case BIND_OPCODE_ADD_ADDR_ULEB:
965 segOffset += read_uleb128(p, end);
966 break;
967 case BIND_OPCODE_DO_BIND:
968 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
969 segOffset += sizeof(pint_t);
970 break;
971 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
972 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
973 segOffset += read_uleb128(p, end) + sizeof(pint_t);
974 break;
975 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
976 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
977 segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
978 break;
979 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
980 count = read_uleb128(p, end);
981 skip = read_uleb128(p, end);
982 for (uint32_t i=0; i < count; ++i) {
983 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
984 segOffset += skip + sizeof(pint_t);
985 }
986 break;
987 default:
988 throwf("unknown weak bind opcode %d", *p);
989 }
990 }
991 }
992
993 }
994
995
996 template <typename A>
997 void DyldInfoPrinter<A>::printLazyBindingInfo()
998 {
999 if ( fInfo == NULL ) {
1000 printf("no compressed dyld info\n");
1001 }
1002 else if ( fInfo->lazy_bind_off() == 0 ) {
1003 printf("no compressed lazy binding info\n");
1004 }
1005 else {
1006 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1007 printf("segment section address index dylib symbol\n");
1008 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
1009 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
1010
1011 uint8_t type = BIND_TYPE_POINTER;
1012 uint8_t segIndex = 0;
1013 uint64_t segOffset = 0;
1014 const char* symbolName = NULL;
1015 const char* fromDylib = "??";
1016 int libraryOrdinal = 0;
1017 int64_t addend = 0;
1018 uint32_t lazy_offset = 0;
1019 pint_t segStartAddr = 0;
1020 const char* segName = "??";
1021 const char* typeName = "??";
1022 for (const uint8_t* p=start; p < end; ) {
1023 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1024 uint8_t opcode = *p & BIND_OPCODE_MASK;
1025 ++p;
1026 switch (opcode) {
1027 case BIND_OPCODE_DONE:
1028 lazy_offset = p-start;
1029 break;
1030 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1031 libraryOrdinal = immediate;
1032 fromDylib = ordinalName(libraryOrdinal);
1033 break;
1034 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1035 libraryOrdinal = read_uleb128(p, end);
1036 fromDylib = ordinalName(libraryOrdinal);
1037 break;
1038 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1039 // the special ordinals are negative numbers
1040 if ( immediate == 0 )
1041 libraryOrdinal = 0;
1042 else {
1043 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1044 libraryOrdinal = signExtended;
1045 }
1046 fromDylib = ordinalName(libraryOrdinal);
1047 break;
1048 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1049 symbolName = (char*)p;
1050 while (*p != '\0')
1051 ++p;
1052 ++p;
1053 break;
1054 case BIND_OPCODE_SET_TYPE_IMM:
1055 type = immediate;
1056 typeName = bindTypeName(type);
1057 break;
1058 case BIND_OPCODE_SET_ADDEND_SLEB:
1059 addend = read_sleb128(p, end);
1060 break;
1061 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1062 segIndex = immediate;
1063 segStartAddr = segStartAddress(segIndex);
1064 segName = segmentName(segIndex);
1065 segOffset = read_uleb128(p, end);
1066 break;
1067 case BIND_OPCODE_ADD_ADDR_ULEB:
1068 segOffset += read_uleb128(p, end);
1069 break;
1070 case BIND_OPCODE_DO_BIND:
1071 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName );
1072 segOffset += sizeof(pint_t);
1073 break;
1074 default:
1075 throwf("bad lazy bind opcode %d", *p);
1076 }
1077 }
1078 }
1079
1080 }
1081
1082 template <typename A>
1083 void DyldInfoPrinter<A>::printLazyBindingOpcodes()
1084 {
1085 if ( fInfo == NULL ) {
1086 printf("no compressed dyld info\n");
1087 }
1088 else if ( fInfo->lazy_bind_off() == 0 ) {
1089 printf("no compressed lazy binding info\n");
1090 }
1091 else {
1092 printf("lazy binding opcodes:\n");
1093 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
1094 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
1095 uint8_t type = BIND_TYPE_POINTER;
1096 uint8_t flags;
1097 uint64_t address = fBaseAddress;
1098 const char* symbolName = NULL;
1099 int libraryOrdinal = 0;
1100 int64_t addend = 0;
1101 uint32_t segmentIndex = 0;
1102 uint32_t count;
1103 uint32_t skip;
1104 for (const uint8_t* p = start; p < end; ) {
1105 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1106 uint8_t opcode = *p & BIND_OPCODE_MASK;
1107 uint32_t opcodeOffset = p-start;
1108 ++p;
1109 switch (opcode) {
1110 case BIND_OPCODE_DONE:
1111 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
1112 break;
1113 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1114 libraryOrdinal = immediate;
1115 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1116 break;
1117 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1118 libraryOrdinal = read_uleb128(p, end);
1119 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
1120 break;
1121 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1122 // the special ordinals are negative numbers
1123 if ( immediate == 0 )
1124 libraryOrdinal = 0;
1125 else {
1126 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1127 libraryOrdinal = signExtended;
1128 }
1129 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1130 break;
1131 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1132 flags = immediate;
1133 symbolName = (char*)p;
1134 while (*p != '\0')
1135 ++p;
1136 ++p;
1137 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
1138 break;
1139 case BIND_OPCODE_SET_TYPE_IMM:
1140 type = immediate;
1141 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
1142 break;
1143 case BIND_OPCODE_SET_ADDEND_SLEB:
1144 addend = read_sleb128(p, end);
1145 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
1146 break;
1147 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1148 segmentIndex = immediate;
1149 address = read_uleb128(p, end);
1150 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
1151 break;
1152 case BIND_OPCODE_ADD_ADDR_ULEB:
1153 skip = read_uleb128(p, end);
1154 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1155 break;
1156 case BIND_OPCODE_DO_BIND:
1157 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
1158 break;
1159 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1160 skip = read_uleb128(p, end);
1161 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1162 break;
1163 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1164 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
1165 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
1166 break;
1167 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1168 count = read_uleb128(p, end);
1169 skip = read_uleb128(p, end);
1170 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
1171 break;
1172 default:
1173 throwf("unknown bind opcode %d", *p);
1174 }
1175 }
1176 }
1177
1178 }
1179
1180
1181 template <typename A>
1182 void DyldInfoPrinter<A>::processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end,
1183 char* cummulativeString, int curStrOffset)
1184 {
1185 const uint8_t terminalSize = *p++;
1186 const uint8_t* children = p + terminalSize;
1187 if ( terminalSize != 0 ) {
1188 uint32_t flags = read_uleb128(p, end);
1189 uint64_t address = read_uleb128(p, end);
1190 if ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
1191 fprintf(stdout, "0x%08llX [weak_def] %s\n", address, cummulativeString);
1192 else
1193 fprintf(stdout, "0x%08llX %s\n", address, cummulativeString);
1194 }
1195 const uint8_t childrenCount = *children++;
1196 const uint8_t* s = children;
1197 for (uint8_t i=0; i < childrenCount; ++i) {
1198 int edgeStrLen = 0;
1199 while (*s != '\0') {
1200 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1201 ++edgeStrLen;
1202 }
1203 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1204 uint32_t childNodeOffet = read_uleb128(s, end);
1205 processExportNode(start, start+childNodeOffet, end, cummulativeString, curStrOffset+edgeStrLen);
1206 }
1207 }
1208
1209 struct SortExportsByAddress
1210 {
1211 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
1212 {
1213 return ( left.address < right.address );
1214 }
1215 };
1216
1217 template <typename A>
1218 void DyldInfoPrinter<A>::printExportInfo()
1219 {
1220 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1221 printf("no compressed export info\n");
1222 }
1223 else {
1224 printf("export information (from trie):\n");
1225 const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
1226 const uint8_t* end = &start[fInfo->export_size()];
1227 std::vector<mach_o::trie::Entry> list;
1228 parseTrie(start, end, list);
1229 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1230 for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) {
1231 const char* flags = "";
1232 if ( it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
1233 flags = "[weak_def] ";
1234 fprintf(stdout, "0x%08llX %s%s\n", fBaseAddress+it->address, flags, it->name);
1235 }
1236 }
1237 }
1238
1239
1240 template <typename A>
1241 void DyldInfoPrinter<A>::processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
1242 const uint8_t* parent, const uint8_t* p,
1243 char* cummulativeString, int curStrOffset)
1244 {
1245 const uint8_t* const me = p;
1246 const uint8_t terminalSize = *p++;
1247 const uint8_t* children = p + terminalSize;
1248 if ( terminalSize != 0 ) {
1249 uint32_t flags = read_uleb128(p, end);
1250 (void)flags; // currently unused
1251 uint64_t address = read_uleb128(p, end);
1252 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address);
1253 }
1254 else {
1255 printf("\tnode%03ld;\n", (long)(me-start));
1256 }
1257 const uint8_t childrenCount = *children++;
1258 const uint8_t* s = children;
1259 for (uint8_t i=0; i < childrenCount; ++i) {
1260 const char* edgeName = (char*)s;
1261 int edgeStrLen = 0;
1262 while (*s != '\0') {
1263 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1264 ++edgeStrLen;
1265 }
1266 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1267 uint32_t childNodeOffet = read_uleb128(s, end);
1268 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me-start), childNodeOffet, edgeName);
1269 processExportGraphNode(start, end, start, start+childNodeOffet, cummulativeString, curStrOffset+edgeStrLen);
1270 }
1271 }
1272
1273 template <typename A>
1274 void DyldInfoPrinter<A>::printExportInfoGraph()
1275 {
1276 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1277 printf("no compressed export info\n");
1278 }
1279 else {
1280 const uint8_t* p = (uint8_t*)fHeader + fInfo->export_off();
1281 const uint8_t* end = &p[fInfo->export_size()];
1282 char cummulativeString[2000];
1283 printf("digraph {\n");
1284 processExportGraphNode(p, end, p, p, cummulativeString, 0);
1285 printf("}\n");
1286 }
1287 }
1288
1289
1290 template <>
1291 ppc::P::uint_t DyldInfoPrinter<ppc>::relocBase()
1292 {
1293 if ( fHeader->flags() & MH_SPLIT_SEGS )
1294 return fFirstWritableSegment->vmaddr();
1295 else
1296 return fFirstSegment->vmaddr();
1297 }
1298
1299 template <>
1300 ppc64::P::uint_t DyldInfoPrinter<ppc64>::relocBase()
1301 {
1302 if ( fWriteableSegmentWithAddrOver4G )
1303 return fFirstWritableSegment->vmaddr();
1304 else
1305 return fFirstSegment->vmaddr();
1306 }
1307
1308 template <>
1309 x86::P::uint_t DyldInfoPrinter<x86>::relocBase()
1310 {
1311 if ( fHeader->flags() & MH_SPLIT_SEGS )
1312 return fFirstWritableSegment->vmaddr();
1313 else
1314 return fFirstSegment->vmaddr();
1315 }
1316
1317 template <>
1318 x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
1319 {
1320 // check for split-seg
1321 return fFirstWritableSegment->vmaddr();
1322 }
1323
1324 template <>
1325 arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
1326 {
1327 if ( fHeader->flags() & MH_SPLIT_SEGS )
1328 return fFirstWritableSegment->vmaddr();
1329 else
1330 return fFirstSegment->vmaddr();
1331 }
1332
1333
1334 template <>
1335 const char* DyldInfoPrinter<ppc>::relocTypeName(uint8_t r_type)
1336 {
1337 if ( r_type == GENERIC_RELOC_VANILLA )
1338 return "pointer";
1339 else if ( r_type == PPC_RELOC_PB_LA_PTR )
1340 return "pb pointer";
1341 else
1342 return "??";
1343 }
1344
1345 template <>
1346 const char* DyldInfoPrinter<ppc64>::relocTypeName(uint8_t r_type)
1347 {
1348 if ( r_type == GENERIC_RELOC_VANILLA )
1349 return "pointer";
1350 else
1351 return "??";
1352 }
1353
1354 template <>
1355 const char* DyldInfoPrinter<x86>::relocTypeName(uint8_t r_type)
1356 {
1357 if ( r_type == GENERIC_RELOC_VANILLA )
1358 return "pointer";
1359 else if ( r_type == GENERIC_RELOC_PB_LA_PTR )
1360 return "pb pointer";
1361 else
1362 return "??";
1363 }
1364
1365 template <>
1366 const char* DyldInfoPrinter<x86_64>::relocTypeName(uint8_t r_type)
1367 {
1368 if ( r_type == X86_64_RELOC_UNSIGNED )
1369 return "pointer";
1370 else
1371 return "??";
1372 }
1373
1374 template <>
1375 const char* DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
1376 {
1377 if ( r_type == ARM_RELOC_VANILLA )
1378 return "pointer";
1379 else if ( r_type == ARM_RELOC_PB_LA_PTR )
1380 return "pb pointer";
1381 else
1382 return "??";
1383 }
1384
1385
1386 template <typename A>
1387 void DyldInfoPrinter<A>::printRelocRebaseInfo()
1388 {
1389 if ( fDynamicSymbolTable == NULL ) {
1390 printf("no classic dynamic symbol table");
1391 }
1392 else {
1393 printf("rebase information (from local relocation records and indirect symbol table):\n");
1394 printf("segment section address type\n");
1395 // walk all local relocations
1396 pint_t rbase = relocBase();
1397 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + fDynamicSymbolTable->locreloff());
1398 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nlocrel()];
1399 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1400 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
1401 pint_t addr = reloc->r_address() + rbase;
1402 uint8_t segIndex = segmentIndexForAddress(addr);
1403 const char* typeName = relocTypeName(reloc->r_type());
1404 const char* segName = segmentName(segIndex);
1405 const char* sectName = sectionName(segIndex, addr);
1406 printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
1407 }
1408 else {
1409 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
1410 pint_t addr = sreloc->r_address() + rbase;
1411 uint8_t segIndex = segmentIndexForAddress(addr);
1412 const char* typeName = relocTypeName(sreloc->r_type());
1413 const char* segName = segmentName(segIndex);
1414 const char* sectName = sectionName(segIndex, addr);
1415 printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
1416 }
1417 }
1418 // look for local non-lazy-pointers
1419 const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
1420 uint8_t segIndex = 0;
1421 for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit, ++segIndex) {
1422 const macho_segment_command<P>* segCmd = *segit;
1423 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
1424 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
1425 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
1426 uint8_t type = sect->flags() & SECTION_TYPE;
1427 if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
1428 uint32_t indirectOffset = sect->reserved1();
1429 uint32_t count = sect->size() / sizeof(pint_t);
1430 for (uint32_t i=0; i < count; ++i) {
1431 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
1432 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
1433 pint_t addr = sect->addr() + i*sizeof(pint_t);
1434 const char* typeName = "pointer";
1435 const char* segName = segmentName(segIndex);
1436 const char* sectName = sectionName(segIndex, addr);
1437 printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
1438 }
1439 }
1440 }
1441 }
1442 }
1443 }
1444 }
1445
1446
1447 template <typename A>
1448 void DyldInfoPrinter<A>::printSymbolTableExportInfo()
1449 {
1450 if ( fDynamicSymbolTable == NULL ) {
1451 printf("no classic dynamic symbol table");
1452 }
1453 else {
1454 printf("export information (from symbol table):\n");
1455 const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
1456 for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
1457 const char* flags = "";
1458 if ( sym->n_desc() & N_WEAK_DEF )
1459 flags = "[weak_def] ";
1460 pint_t thumb = 0;
1461 if ( sym->n_desc() & N_ARM_THUMB_DEF )
1462 thumb = 1;
1463 printf("0x%08llX %s%s\n", sym->n_value()+thumb, flags, &fStrings[sym->n_strx()]);
1464 }
1465 }
1466 }
1467
1468
1469 template <typename A>
1470 void DyldInfoPrinter<A>::printClassicBindingInfo()
1471 {
1472 if ( fDynamicSymbolTable == NULL ) {
1473 printf("no classic dynamic symbol table");
1474 }
1475 else {
1476 printf("binding information (from relocations and indirect symbol table):\n");
1477 printf("segment section address type weak addend dylib symbol\n");
1478 // walk all external relocations
1479 pint_t rbase = relocBase();
1480 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + fDynamicSymbolTable->extreloff());
1481 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nextrel()];
1482 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1483 pint_t addr = reloc->r_address() + rbase;
1484 uint32_t symbolIndex = reloc->r_symbolnum();
1485 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
1486 const char* symbolName = &fStrings[sym->n_strx()];
1487 const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : "";
1488 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
1489 uint8_t segIndex = segmentIndexForAddress(addr);
1490 const char* typeName = relocTypeName(reloc->r_type());
1491 const char* segName = segmentName(segIndex);
1492 const char* sectName = sectionName(segIndex, addr);
1493 const pint_t* addressMapped = mappedAddressForVMAddress(addr);
1494 int64_t addend = P::getP(*addressMapped);
1495 if ( fHeader->flags() & MH_PREBOUND ) {
1496 // In prebound binaries the content is already pointing to the target.
1497 // To get the addend requires subtracting out the base address it was prebound to.
1498 addend -= sym->n_value();
1499 }
1500 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr,
1501 typeName, weak_import, addend, fromDylib, symbolName);
1502 }
1503 // look for non-lazy pointers
1504 const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
1505 for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) {
1506 const macho_segment_command<P>* segCmd = *segit;
1507 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
1508 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
1509 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
1510 uint8_t type = sect->flags() & SECTION_TYPE;
1511 if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
1512 uint32_t indirectOffset = sect->reserved1();
1513 uint32_t count = sect->size() / sizeof(pint_t);
1514 for (uint32_t i=0; i < count; ++i) {
1515 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
1516 if ( symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
1517 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
1518 const char* symbolName = &fStrings[sym->n_strx()];
1519 const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : "";
1520 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
1521 pint_t addr = sect->addr() + i*sizeof(pint_t);
1522 uint8_t segIndex = segmentIndexForAddress(addr);
1523 const char* typeName = "pointer";
1524 const char* segName = segmentName(segIndex);
1525 const char* sectName = sectionName(segIndex, addr);
1526 int64_t addend = 0;
1527 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr,
1528 typeName, weak_import, addend, fromDylib, symbolName);
1529 }
1530 }
1531 }
1532 }
1533 }
1534 }
1535 }
1536
1537
1538 template <typename A>
1539 void DyldInfoPrinter<A>::printClassicLazyBindingInfo()
1540 {
1541 if ( fDynamicSymbolTable == NULL ) {
1542 printf("no classic dynamic symbol table");
1543 }
1544 else {
1545 printf("lazy binding information (from section records and indirect symbol table):\n");
1546 printf("segment section address index dylib symbol\n");
1547 const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
1548 for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) {
1549 const macho_segment_command<P>* segCmd = *segit;
1550 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
1551 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
1552 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
1553 uint8_t type = sect->flags() & SECTION_TYPE;
1554 if ( type == S_LAZY_SYMBOL_POINTERS ) {
1555 uint32_t indirectOffset = sect->reserved1();
1556 uint32_t count = sect->size() / sizeof(pint_t);
1557 for (uint32_t i=0; i < count; ++i) {
1558 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
1559 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
1560 const char* symbolName = &fStrings[sym->n_strx()];
1561 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
1562 pint_t addr = sect->addr() + i*sizeof(pint_t);
1563 uint8_t segIndex = segmentIndexForAddress(addr);
1564 const char* segName = segmentName(segIndex);
1565 const char* sectName = sectionName(segIndex, addr);
1566 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName);
1567 }
1568 }
1569 else if ( (type == S_SYMBOL_STUBS) && (((sect->flags() & S_ATTR_SELF_MODIFYING_CODE) != 0)) && (sect->reserved2() == 5) ) {
1570 // i386 self-modifying stubs
1571 uint32_t indirectOffset = sect->reserved1();
1572 uint32_t count = sect->size() / 5;
1573 for (uint32_t i=0; i < count; ++i) {
1574 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
1575 if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
1576 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
1577 const char* symbolName = &fStrings[sym->n_strx()];
1578 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
1579 pint_t addr = sect->addr() + i*5;
1580 uint8_t segIndex = segmentIndexForAddress(addr);
1581 const char* segName = segmentName(segIndex);
1582 const char* sectName = sectionName(segIndex, addr);
1583 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName);
1584 }
1585 }
1586 }
1587 }
1588 }
1589 }
1590 }
1591
1592 static void dump(const char* path)
1593 {
1594 struct stat stat_buf;
1595
1596 try {
1597 int fd = ::open(path, O_RDONLY, 0);
1598 if ( fd == -1 )
1599 throw "cannot open file";
1600 if ( ::fstat(fd, &stat_buf) != 0 )
1601 throwf("fstat(%s) failed, errno=%d\n", path, errno);
1602 uint32_t length = stat_buf.st_size;
1603 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
1604 if ( p == ((uint8_t*)(-1)) )
1605 throw "cannot map file";
1606 ::close(fd);
1607 const mach_header* mh = (mach_header*)p;
1608 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
1609 const struct fat_header* fh = (struct fat_header*)p;
1610 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
1611 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
1612 size_t offset = OSSwapBigToHostInt32(archs[i].offset);
1613 size_t size = OSSwapBigToHostInt32(archs[i].size);
1614 cpu_type_t cputype = OSSwapBigToHostInt32(archs[i].cputype);
1615 cpu_type_t cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);
1616 if ( (cputype == sPreferredArch)
1617 && ((sPreferredSubArch==0) || (sPreferredSubArch==cpusubtype)) ) {
1618 switch(cputype) {
1619 case CPU_TYPE_POWERPC:
1620 if ( DyldInfoPrinter<ppc>::validFile(p + offset) )
1621 DyldInfoPrinter<ppc>::make(p + offset, size, path);
1622 else
1623 throw "in universal file, ppc slice does not contain ppc mach-o";
1624 break;
1625 case CPU_TYPE_I386:
1626 if ( DyldInfoPrinter<x86>::validFile(p + offset) )
1627 DyldInfoPrinter<x86>::make(p + offset, size, path);
1628 else
1629 throw "in universal file, i386 slice does not contain i386 mach-o";
1630 break;
1631 case CPU_TYPE_POWERPC64:
1632 if ( DyldInfoPrinter<ppc64>::validFile(p + offset) )
1633 DyldInfoPrinter<ppc64>::make(p + offset, size, path);
1634 else
1635 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
1636 break;
1637 case CPU_TYPE_X86_64:
1638 if ( DyldInfoPrinter<x86_64>::validFile(p + offset) )
1639 DyldInfoPrinter<x86_64>::make(p + offset, size, path);
1640 else
1641 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
1642 break;
1643 case CPU_TYPE_ARM:
1644 if ( DyldInfoPrinter<arm>::validFile(p + offset) )
1645 DyldInfoPrinter<arm>::make(p + offset, size, path);
1646 else
1647 throw "in universal file, arm slice does not contain arm mach-o";
1648 break;
1649 default:
1650 throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
1651 }
1652 }
1653 }
1654 }
1655 else if ( DyldInfoPrinter<x86>::validFile(p) ) {
1656 DyldInfoPrinter<x86>::make(p, length, path);
1657 }
1658 else if ( DyldInfoPrinter<ppc>::validFile(p) ) {
1659 DyldInfoPrinter<ppc>::make(p, length, path);
1660 }
1661 else if ( DyldInfoPrinter<ppc64>::validFile(p) ) {
1662 DyldInfoPrinter<ppc64>::make(p, length, path);
1663 }
1664 else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
1665 DyldInfoPrinter<x86_64>::make(p, length, path);
1666 }
1667 else if ( DyldInfoPrinter<arm>::validFile(p) ) {
1668 DyldInfoPrinter<arm>::make(p, length, path);
1669 }
1670 else {
1671 throw "not a known file type";
1672 }
1673 }
1674 catch (const char* msg) {
1675 throwf("%s in %s", msg, path);
1676 }
1677 }
1678
1679 static void usage()
1680 {
1681 fprintf(stderr, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
1682 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
1683 "\t-bind print addresses dyld will set based on symbolic lookups\n"
1684 "\t-weak_bind print symbols which dyld must coalesce\n"
1685 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
1686 "\t-export print addresses of all symbols this file exports\n"
1687 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
1688 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
1689 );
1690 }
1691
1692
1693 int main(int argc, const char* argv[])
1694 {
1695 if ( argc == 1 ) {
1696 usage();
1697 return 0;
1698 }
1699
1700 try {
1701 std::vector<const char*> files;
1702 for(int i=1; i < argc; ++i) {
1703 const char* arg = argv[i];
1704 if ( arg[0] == '-' ) {
1705 if ( strcmp(arg, "-arch") == 0 ) {
1706 const char* arch = ++i<argc? argv[i]: "";
1707 if ( strcmp(arch, "ppc64") == 0 )
1708 sPreferredArch = CPU_TYPE_POWERPC64;
1709 else if ( strcmp(arch, "ppc") == 0 )
1710 sPreferredArch = CPU_TYPE_POWERPC;
1711 else if ( strcmp(arch, "i386") == 0 )
1712 sPreferredArch = CPU_TYPE_I386;
1713 else if ( strcmp(arch, "x86_64") == 0 )
1714 sPreferredArch = CPU_TYPE_X86_64;
1715 else if ( strcmp(arch, "arm") == 0 )
1716 sPreferredArch = CPU_TYPE_ARM;
1717 else if ( strcmp(arch, "armv4t") == 0 ) {
1718 sPreferredArch = CPU_TYPE_ARM;
1719 sPreferredSubArch = CPU_SUBTYPE_ARM_V4T;
1720 }
1721 else if ( strcmp(arch, "armv5") == 0 ) {
1722 sPreferredArch = CPU_TYPE_ARM;
1723 sPreferredSubArch = CPU_SUBTYPE_ARM_V5TEJ;
1724 }
1725 else if ( strcmp(arch, "armv6") == 0 ) {
1726 sPreferredArch = CPU_TYPE_ARM;
1727 sPreferredSubArch = CPU_SUBTYPE_ARM_V6;
1728 }
1729 else if ( strcmp(arch, "armv7") == 0 ) {
1730 sPreferredArch = CPU_TYPE_ARM;
1731 sPreferredSubArch = CPU_SUBTYPE_ARM_V7;
1732 }
1733 else
1734 throwf("unknown architecture %s", arch);
1735 }
1736 else if ( strcmp(arg, "-rebase") == 0 ) {
1737 printRebase = true;
1738 }
1739 else if ( strcmp(arg, "-bind") == 0 ) {
1740 printBind = true;
1741 }
1742 else if ( strcmp(arg, "-weak_bind") == 0 ) {
1743 printWeakBind = true;
1744 }
1745 else if ( strcmp(arg, "-lazy_bind") == 0 ) {
1746 printLazyBind = true;
1747 }
1748 else if ( strcmp(arg, "-export") == 0 ) {
1749 printExport = true;
1750 }
1751 else if ( strcmp(arg, "-opcodes") == 0 ) {
1752 printOpcodes = true;
1753 }
1754 else if ( strcmp(arg, "-export_dot") == 0 ) {
1755 printExportGraph = true;
1756 }
1757 else {
1758 throwf("unknown option: %s\n", arg);
1759 }
1760 }
1761 else {
1762 files.push_back(arg);
1763 }
1764 }
1765 if ( files.size() == 0 )
1766 usage();
1767 if ( files.size() == 1 ) {
1768 dump(files[0]);
1769 }
1770 else {
1771 for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
1772 printf("\n%s:\n", *it);
1773 dump(*it);
1774 }
1775 }
1776 }
1777 catch (const char* msg) {
1778 fprintf(stderr, "dyldinfo failed: %s\n", msg);
1779 return 1;
1780 }
1781
1782 return 0;
1783 }
1784
1785
1786