1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2008 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
36 #include <ext/hash_set>
38 #include "MachOFileAbstraction.hpp"
39 #include "Architectures.hpp"
40 #include "MachOTrie.hpp"
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
;
52 __attribute__((noreturn
))
53 void throwf(const char* format
, ...)
57 va_start(list
, format
);
58 vasprintf(&p
, format
, list
);
70 static bool validFile(const uint8_t* fileContent
);
71 static DyldInfoPrinter
<A
>* make(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
)
72 { return new DyldInfoPrinter
<A
>(fileContent
, fileLength
, path
); }
73 virtual ~DyldInfoPrinter() {}
77 typedef typename
A::P P
;
78 typedef typename
A::P::E E
;
79 typedef typename
A::P::uint_t pint_t
;
84 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
87 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> StringSet
;
89 DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
);
90 void printRebaseInfo();
91 void printRebaseInfoOpcodes();
92 void printBindingInfo();
93 void printWeakBindingInfo();
94 void printLazyBindingInfo();
95 void printBindingInfoOpcodes(bool weakBinding
);
96 void printWeakBindingInfoOpcodes();
97 void printLazyBindingOpcodes();
98 void printExportInfo();
99 void printExportInfoGraph();
100 void processExportNode(const uint8_t* const start
, const uint8_t* p
, const uint8_t* const end
,
101 char* cummulativeString
, int curStrOffset
);
102 void processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
103 const uint8_t* parent
, const uint8_t* p
,
104 char* cummulativeString
, int curStrOffset
);
105 const char* rebaseTypeName(uint8_t type
);
106 const char* bindTypeName(uint8_t type
);
107 pint_t
segStartAddress(uint8_t segIndex
);
108 const char* segmentName(uint8_t segIndex
);
109 const char* sectionName(uint8_t segIndex
, pint_t address
);
110 const char* getSegAndSectName(uint8_t segIndex
, pint_t address
);
111 const char* ordinalName(int libraryOrdinal
);
115 const macho_header
<P
>* fHeader
;
117 const char* fStrings
;
118 const char* fStringsEnd
;
119 const macho_nlist
<P
>* fSymbols
;
120 uint32_t fSymbolCount
;
121 const macho_dyld_info_command
<P
>* fInfo
;
122 uint64_t fBaseAddress
;
123 std::vector
<const macho_segment_command
<P
>*>fSegments
;
124 std::vector
<const char*> fDylibs
;
130 bool DyldInfoPrinter
<ppc
>::validFile(const uint8_t* fileContent
)
132 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
133 if ( header
->magic() != MH_MAGIC
)
135 if ( header
->cputype() != CPU_TYPE_POWERPC
)
137 switch (header
->filetype()) {
148 bool DyldInfoPrinter
<ppc64
>::validFile(const uint8_t* fileContent
)
150 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
151 if ( header
->magic() != MH_MAGIC_64
)
153 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
155 switch (header
->filetype()) {
166 bool DyldInfoPrinter
<x86
>::validFile(const uint8_t* fileContent
)
168 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
169 if ( header
->magic() != MH_MAGIC
)
171 if ( header
->cputype() != CPU_TYPE_I386
)
173 switch (header
->filetype()) {
184 bool DyldInfoPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
186 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
187 if ( header
->magic() != MH_MAGIC_64
)
189 if ( header
->cputype() != CPU_TYPE_X86_64
)
191 switch (header
->filetype()) {
202 bool DyldInfoPrinter
<arm
>::validFile(const uint8_t* fileContent
)
204 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
205 if ( header
->magic() != MH_MAGIC
)
207 if ( header
->cputype() != CPU_TYPE_ARM
)
209 switch (header
->filetype()) {
220 template <typename A
>
221 DyldInfoPrinter
<A
>::DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
)
222 : fHeader(NULL
), fLength(fileLength
),
223 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fInfo(NULL
), fBaseAddress(0)
226 if ( ! validFile(fileContent
) )
227 throw "not a mach-o file that can be checked";
229 fPath
= strdup(path
);
230 fHeader
= (const macho_header
<P
>*)fileContent
;
233 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
234 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
235 const uint32_t cmd_count
= fHeader
->ncmds();
236 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
237 const macho_load_command
<P
>* cmd
= cmds
;
238 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
239 uint32_t size
= cmd
->cmdsize();
240 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
241 if ( endOfCmd
> endOfLoadCommands
)
242 throwf("load command #%d extends beyond the end of the load commands", i
);
243 if ( endOfCmd
> endOfFile
)
244 throwf("load command #%d extends beyond the end of the file", i
);
245 switch ( cmd
->cmd() ) {
247 case LC_DYLD_INFO_ONLY
:
248 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
250 case macho_segment_command
<P
>::CMD
:
252 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
253 fSegments
.push_back(segCmd
);
254 if ( (segCmd
->fileoff() == 0) && (segCmd
->filesize() != 0) )
255 fBaseAddress
= segCmd
->vmaddr();
259 case LC_LOAD_WEAK_DYLIB
:
260 case LC_REEXPORT_DYLIB
:
261 case LC_LAZY_LOAD_DYLIB
:
263 const macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
264 const char* lastSlash
= strrchr(dylib
->name(), '/');
265 const char* leafName
= (lastSlash
!= NULL
) ? lastSlash
+1 : dylib
->name();
266 const char* firstDot
= strchr(leafName
, '.');
267 if ( firstDot
!= NULL
) {
268 char* t
= strdup(leafName
);
269 t
[firstDot
-leafName
] = '\0';
270 fDylibs
.push_back(t
);
273 fDylibs
.push_back(leafName
);
278 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
286 printWeakBindingInfo();
288 printLazyBindingInfo();
291 if ( printOpcodes
) {
292 printRebaseInfoOpcodes();
293 printBindingInfoOpcodes(false);
294 printBindingInfoOpcodes(true);
295 printLazyBindingOpcodes();
297 if ( printExportGraph
)
298 printExportInfoGraph();
301 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
307 throwf("malformed uleb128");
309 uint64_t slice
= *p
& 0x7f;
311 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
312 throwf("uleb128 too big");
314 result
|= (slice
<< bit
);
322 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
329 throwf("malformed sleb128");
331 result
|= ((byte
& 0x7f) << bit
);
333 } while (byte
& 0x80);
334 // sign extend negative numbers
335 if ( (byte
& 0x40) != 0 )
336 result
|= (-1LL) << bit
;
341 template <typename A
>
342 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
345 case REBASE_TYPE_POINTER
:
347 case REBASE_TYPE_TEXT_ABSOLUTE32
:
349 case REBASE_TYPE_TEXT_PCREL32
:
352 return "!!unknown!!";
356 template <typename A
>
357 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
360 case BIND_TYPE_POINTER
:
362 case BIND_TYPE_TEXT_ABSOLUTE32
:
364 case BIND_TYPE_TEXT_PCREL32
:
367 return "!!unknown!!";
371 template <typename A
>
372 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
374 if ( segIndex
> fSegments
.size() )
375 throw "segment index out of range";
376 return fSegments
[segIndex
]->vmaddr();
379 template <typename A
>
380 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
382 if ( segIndex
> fSegments
.size() )
383 throw "segment index out of range";
384 return fSegments
[segIndex
]->segname();
387 template <typename A
>
388 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
390 if ( segIndex
> fSegments
.size() )
391 throw "segment index out of range";
392 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
393 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
394 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
395 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
396 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
397 if ( strlen(sect
->sectname()) > 15 ) {
398 static char temp
[18];
399 strlcpy(temp
, sect
->sectname(), 17);
403 return sect
->sectname();
410 template <typename A
>
411 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
413 static char buffer
[64];
414 strcpy(buffer
, segmentName(segIndex
));
416 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
417 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
418 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
419 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
420 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
421 // section name may not be zero terminated
422 char* end
= &buffer
[strlen(buffer
)];
423 strlcpy(end
, sect
->sectname(), 16);
430 template <typename A
>
431 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
433 switch ( libraryOrdinal
) {
434 case BIND_SPECIAL_DYLIB_SELF
:
436 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
437 return "main-executable";
438 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
439 return "flat-namespace";
441 if ( libraryOrdinal
< BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
442 throw "unknown special ordinal";
443 if ( libraryOrdinal
> fDylibs
.size() )
444 throw "libraryOrdinal out of range";
445 return fDylibs
[libraryOrdinal
-1];
449 template <typename A
>
450 void DyldInfoPrinter
<A
>::printRebaseInfo()
452 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
453 printf("no compressed rebase info\n");
456 printf("rebase information:\n");
457 printf("segment section address type\n");
459 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
460 const uint8_t* end
= &p
[fInfo
->rebase_size()];
463 uint64_t segOffset
= 0;
467 pint_t segStartAddr
= 0;
468 const char* segName
= "??";
469 const char* typeName
= "??";
471 while ( !done
&& (p
< end
) ) {
472 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
473 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
476 case REBASE_OPCODE_DONE
:
479 case REBASE_OPCODE_SET_TYPE_IMM
:
481 typeName
= rebaseTypeName(type
);
483 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
484 segIndex
= immediate
;
485 segStartAddr
= segStartAddress(segIndex
);
486 segName
= segmentName(segIndex
);
487 segOffset
= read_uleb128(p
, end
);
489 case REBASE_OPCODE_ADD_ADDR_ULEB
:
490 segOffset
+= read_uleb128(p
, end
);
492 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
493 segOffset
+= immediate
*sizeof(pint_t
);
495 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
496 for (int i
=0; i
< immediate
; ++i
) {
497 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
498 segOffset
+= sizeof(pint_t
);
501 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
502 count
= read_uleb128(p
, end
);
503 for (uint32_t i
=0; i
< count
; ++i
) {
504 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
505 segOffset
+= sizeof(pint_t
);
508 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
509 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
510 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
512 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
513 count
= read_uleb128(p
, end
);
514 skip
= read_uleb128(p
, end
);
515 for (uint32_t i
=0; i
< count
; ++i
) {
516 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
517 segOffset
+= skip
+ sizeof(pint_t
);
521 throwf("bad rebase opcode %d", *p
);
530 template <typename A
>
531 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
533 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
534 printf("no compressed rebase info\n");
537 printf("rebase opcodes:\n");
538 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
539 const uint8_t* end
= &p
[fInfo
->rebase_size()];
542 uint64_t address
= fBaseAddress
;
545 unsigned int segmentIndex
;
547 while ( !done
&& (p
< end
) ) {
548 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
549 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
552 case REBASE_OPCODE_DONE
:
554 printf("REBASE_OPCODE_DONE()\n");
556 case REBASE_OPCODE_SET_TYPE_IMM
:
558 printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type
);
560 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
561 segmentIndex
= immediate
;
562 address
= read_uleb128(p
, end
);
563 printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex
, address
);
565 case REBASE_OPCODE_ADD_ADDR_ULEB
:
566 address
= read_uleb128(p
, end
);
567 printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address
);
569 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
570 address
= immediate
*sizeof(pint_t
);
571 printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address
);
573 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
574 printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate
);
576 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
577 count
= read_uleb128(p
, end
);
578 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count
);
580 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
581 skip
= read_uleb128(p
, end
) + sizeof(pint_t
);
582 printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip
);
584 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
585 count
= read_uleb128(p
, end
);
586 skip
= read_uleb128(p
, end
);
587 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count
, skip
);
590 throwf("bad rebase opcode %d", *p
);
602 template <typename A
>
603 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
605 if ( fInfo
== NULL
) {
606 printf("no compressed binding info\n");
608 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
609 printf("no compressed binding info\n");
611 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
612 printf("no compressed weak binding info\n");
615 const uint8_t* start
;
618 printf("weak binding opcodes:\n");
619 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
620 end
= &start
[fInfo
->weak_bind_size()];
623 printf("binding opcodes:\n");
624 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
625 end
= &start
[fInfo
->bind_size()];
627 const uint8_t* p
= start
;
630 uint64_t address
= fBaseAddress
;
631 const char* symbolName
= NULL
;
632 int libraryOrdinal
= 0;
634 uint32_t segmentIndex
= 0;
638 while ( !done
&& (p
< end
) ) {
639 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
640 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
641 uint32_t opcodeOffset
= p
-start
;
644 case BIND_OPCODE_DONE
:
646 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
648 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
649 libraryOrdinal
= immediate
;
650 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
652 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
653 libraryOrdinal
= read_uleb128(p
, end
);
654 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
656 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
657 // the special ordinals are negative numbers
658 if ( immediate
== 0 )
661 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
662 libraryOrdinal
= signExtended
;
664 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
666 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
668 symbolName
= (char*)p
;
672 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
674 case BIND_OPCODE_SET_TYPE_IMM
:
676 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
678 case BIND_OPCODE_SET_ADDEND_SLEB
:
679 addend
= read_sleb128(p
, end
);
680 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
682 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
683 segmentIndex
= immediate
;
684 address
= read_uleb128(p
, end
);
685 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
687 case BIND_OPCODE_ADD_ADDR_ULEB
:
688 skip
= read_uleb128(p
, end
);
689 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
691 case BIND_OPCODE_DO_BIND
:
692 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
694 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
695 skip
= read_uleb128(p
, end
);
696 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
698 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
699 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
700 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
702 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
703 count
= read_uleb128(p
, end
);
704 skip
= read_uleb128(p
, end
);
705 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
708 throwf("unknown bind opcode %d", *p
);
717 template <typename A
>
718 void DyldInfoPrinter
<A
>::printBindingInfo()
720 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
721 printf("no compressed binding info\n");
724 printf("bind information:\n");
725 printf("segment section address type weak addend dylib symbol\n");
726 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->bind_off();
727 const uint8_t* end
= &p
[fInfo
->bind_size()];
730 uint8_t segIndex
= 0;
731 uint64_t segOffset
= 0;
732 const char* symbolName
= NULL
;
733 const char* fromDylib
= "??";
734 int libraryOrdinal
= 0;
738 pint_t segStartAddr
= 0;
739 const char* segName
= "??";
740 const char* typeName
= "??";
741 const char* weak_import
= "";
743 while ( !done
&& (p
< end
) ) {
744 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
745 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
748 case BIND_OPCODE_DONE
:
751 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
752 libraryOrdinal
= immediate
;
753 fromDylib
= ordinalName(libraryOrdinal
);
755 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
756 libraryOrdinal
= read_uleb128(p
, end
);
757 fromDylib
= ordinalName(libraryOrdinal
);
759 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
760 // the special ordinals are negative numbers
761 if ( immediate
== 0 )
764 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
765 libraryOrdinal
= signExtended
;
767 fromDylib
= ordinalName(libraryOrdinal
);
769 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
770 symbolName
= (char*)p
;
774 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
775 weak_import
= "weak";
779 case BIND_OPCODE_SET_TYPE_IMM
:
781 typeName
= bindTypeName(type
);
783 case BIND_OPCODE_SET_ADDEND_SLEB
:
784 addend
= read_sleb128(p
, end
);
786 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
787 segIndex
= immediate
;
788 segStartAddr
= segStartAddress(segIndex
);
789 segName
= segmentName(segIndex
);
790 segOffset
= read_uleb128(p
, end
);
792 case BIND_OPCODE_ADD_ADDR_ULEB
:
793 segOffset
+= read_uleb128(p
, end
);
795 case BIND_OPCODE_DO_BIND
:
796 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, weak_import
, addend
, fromDylib
, symbolName
);
797 segOffset
+= sizeof(pint_t
);
799 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
800 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, weak_import
, addend
, fromDylib
, symbolName
);
801 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
803 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
804 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, weak_import
, addend
, fromDylib
, symbolName
);
805 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
807 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
808 count
= read_uleb128(p
, end
);
809 skip
= read_uleb128(p
, end
);
810 for (uint32_t i
=0; i
< count
; ++i
) {
811 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, weak_import
, addend
, fromDylib
, symbolName
);
812 segOffset
+= skip
+ sizeof(pint_t
);
816 throwf("bad bind opcode %d", *p
);
823 template <typename A
>
824 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
826 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
827 printf("no weak binding\n");
830 printf("weak binding information:\n");
831 printf("segment section address type addend symbol\n");
832 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
833 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
836 uint8_t segIndex
= 0;
837 uint64_t segOffset
= 0;
838 const char* symbolName
= NULL
;
842 pint_t segStartAddr
= 0;
843 const char* segName
= "??";
844 const char* typeName
= "??";
846 while ( !done
&& (p
< end
) ) {
847 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
848 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
851 case BIND_OPCODE_DONE
:
854 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
855 symbolName
= (char*)p
;
859 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
860 printf(" strong %s\n", symbolName
);
862 case BIND_OPCODE_SET_TYPE_IMM
:
864 typeName
= bindTypeName(type
);
866 case BIND_OPCODE_SET_ADDEND_SLEB
:
867 addend
= read_sleb128(p
, end
);
869 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
870 segIndex
= immediate
;
871 segStartAddr
= segStartAddress(segIndex
);
872 segName
= segmentName(segIndex
);
873 segOffset
= read_uleb128(p
, end
);
875 case BIND_OPCODE_ADD_ADDR_ULEB
:
876 segOffset
+= read_uleb128(p
, end
);
878 case BIND_OPCODE_DO_BIND
:
879 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
880 segOffset
+= sizeof(pint_t
);
882 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
883 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
884 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
886 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
887 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
888 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
890 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
891 count
= read_uleb128(p
, end
);
892 skip
= read_uleb128(p
, end
);
893 for (uint32_t i
=0; i
< count
; ++i
) {
894 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
895 segOffset
+= skip
+ sizeof(pint_t
);
899 throwf("unknown weak bind opcode %d", *p
);
907 template <typename A
>
908 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
910 if ( fInfo
== NULL
) {
911 printf("no compressed dyld info\n");
913 else if ( fInfo
->lazy_bind_off() == 0 ) {
914 printf("no compressed lazy binding info\n");
917 printf("lazy binding information:\n");
918 printf("segment section address index dylib symbol\n");
919 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
920 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
922 uint8_t type
= BIND_TYPE_POINTER
;
923 uint8_t segIndex
= 0;
924 uint64_t segOffset
= 0;
925 const char* symbolName
= NULL
;
926 const char* fromDylib
= "??";
927 int libraryOrdinal
= 0;
929 uint32_t lazy_offset
= 0;
930 pint_t segStartAddr
= 0;
931 const char* segName
= "??";
932 const char* typeName
= "??";
933 for (const uint8_t* p
=start
; p
< end
; ) {
934 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
935 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
938 case BIND_OPCODE_DONE
:
939 lazy_offset
= p
-start
;
941 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
942 libraryOrdinal
= immediate
;
943 fromDylib
= ordinalName(libraryOrdinal
);
945 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
946 libraryOrdinal
= read_uleb128(p
, end
);
947 fromDylib
= ordinalName(libraryOrdinal
);
949 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
950 // the special ordinals are negative numbers
951 if ( immediate
== 0 )
954 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
955 libraryOrdinal
= signExtended
;
957 fromDylib
= ordinalName(libraryOrdinal
);
959 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
960 symbolName
= (char*)p
;
965 case BIND_OPCODE_SET_TYPE_IMM
:
967 typeName
= bindTypeName(type
);
969 case BIND_OPCODE_SET_ADDEND_SLEB
:
970 addend
= read_sleb128(p
, end
);
972 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
973 segIndex
= immediate
;
974 segStartAddr
= segStartAddress(segIndex
);
975 segName
= segmentName(segIndex
);
976 segOffset
= read_uleb128(p
, end
);
978 case BIND_OPCODE_ADD_ADDR_ULEB
:
979 segOffset
+= read_uleb128(p
, end
);
981 case BIND_OPCODE_DO_BIND
:
982 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
);
983 segOffset
+= sizeof(pint_t
);
986 throwf("bad lazy bind opcode %d", *p
);
994 uint8_t type
= BIND_TYPE_POINTER
;
996 uint64_t address
= fBaseAddress
;
997 const char* symbolName
= NULL
;
998 int libraryOrdinal
= 0;
1000 uint32_t segmentIndex
= 0;
1003 for (const uint8_t* p
= start
; p
< end
; ) {
1004 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1005 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1006 uint32_t opcodeOffset
= p
-start
;
1009 case BIND_OPCODE_DONE
:
1010 printf("0x%08X BIND_OPCODE_DONE\n", opcodeOffset
);
1012 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1013 libraryOrdinal
= immediate
;
1014 printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1016 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1017 libraryOrdinal
= read_uleb128(p
, end
);
1018 printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1020 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1021 // the special ordinals are negative numbers
1022 if ( immediate
== 0 )
1025 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1026 libraryOrdinal
= signExtended
;
1028 printf("0x%08X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1030 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1032 symbolName
= (char*)p
;
1036 printf("0x%08X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1038 case BIND_OPCODE_SET_TYPE_IMM
:
1040 printf("0x%08X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1042 case BIND_OPCODE_SET_ADDEND_SLEB
:
1043 addend
= read_sleb128(p
, end
);
1044 printf("0x%08X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1046 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1047 segmentIndex
= immediate
;
1048 address
= read_uleb128(p
, end
);
1049 printf("0x%08X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1051 case BIND_OPCODE_ADD_ADDR_ULEB
:
1052 skip
= read_uleb128(p
, end
);
1053 printf("0x%08X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1055 case BIND_OPCODE_DO_BIND
:
1056 printf("0x%08X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1058 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1059 skip
= read_uleb128(p
, end
);
1060 printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1062 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1063 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1064 printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1066 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1067 count
= read_uleb128(p
, end
);
1068 skip
= read_uleb128(p
, end
);
1069 printf("0x%08X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1072 throwf("unknown bind opcode %d", *p
);
1077 template <typename A
>
1078 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1080 if ( fInfo
== NULL
) {
1081 printf("no compressed dyld info\n");
1083 else if ( fInfo
->lazy_bind_off() == 0 ) {
1084 printf("no compressed lazy binding info\n");
1087 printf("lazy binding opcodes:\n");
1088 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1089 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1090 uint8_t type
= BIND_TYPE_POINTER
;
1092 uint64_t address
= fBaseAddress
;
1093 const char* symbolName
= NULL
;
1094 int libraryOrdinal
= 0;
1096 uint32_t segmentIndex
= 0;
1099 for (const uint8_t* p
= start
; p
< end
; ) {
1100 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1101 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1102 uint32_t opcodeOffset
= p
-start
;
1105 case BIND_OPCODE_DONE
:
1106 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1108 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1109 libraryOrdinal
= immediate
;
1110 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1112 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1113 libraryOrdinal
= read_uleb128(p
, end
);
1114 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1116 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1117 // the special ordinals are negative numbers
1118 if ( immediate
== 0 )
1121 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1122 libraryOrdinal
= signExtended
;
1124 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1126 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1128 symbolName
= (char*)p
;
1132 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1134 case BIND_OPCODE_SET_TYPE_IMM
:
1136 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1138 case BIND_OPCODE_SET_ADDEND_SLEB
:
1139 addend
= read_sleb128(p
, end
);
1140 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1142 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1143 segmentIndex
= immediate
;
1144 address
= read_uleb128(p
, end
);
1145 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1147 case BIND_OPCODE_ADD_ADDR_ULEB
:
1148 skip
= read_uleb128(p
, end
);
1149 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1151 case BIND_OPCODE_DO_BIND
:
1152 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1154 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1155 skip
= read_uleb128(p
, end
);
1156 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1158 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1159 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1160 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1162 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1163 count
= read_uleb128(p
, end
);
1164 skip
= read_uleb128(p
, end
);
1165 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1168 throwf("unknown bind opcode %d", *p
);
1176 template <typename A
>
1177 void DyldInfoPrinter
<A
>::processExportNode(const uint8_t* const start
, const uint8_t* p
, const uint8_t* const end
,
1178 char* cummulativeString
, int curStrOffset
)
1180 const uint8_t terminalSize
= *p
++;
1181 const uint8_t* children
= p
+ terminalSize
;
1182 if ( terminalSize
!= 0 ) {
1183 uint32_t flags
= read_uleb128(p
, end
);
1184 uint64_t address
= read_uleb128(p
, end
);
1185 if ( flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
)
1186 fprintf(stdout
, "0x%08llX [weak_def] %s\n", address
, cummulativeString
);
1188 fprintf(stdout
, "0x%08llX %s\n", address
, cummulativeString
);
1190 const uint8_t childrenCount
= *children
++;
1191 const uint8_t* s
= children
;
1192 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1194 while (*s
!= '\0') {
1195 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1198 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1199 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1200 processExportNode(start
, start
+childNodeOffet
, end
, cummulativeString
, curStrOffset
+edgeStrLen
);
1204 struct SortExportsByAddress
1206 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1208 return ( left
.address
< right
.address
);
1212 template <typename A
>
1213 void DyldInfoPrinter
<A
>::printExportInfo()
1215 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1216 printf("no compressed export info\n");
1219 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1220 const uint8_t* end
= &start
[fInfo
->export_size()];
1221 std::vector
<mach_o::trie::Entry
> list
;
1222 parseTrie(start
, end
, list
);
1223 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1224 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1225 const char* flags
= "";
1226 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
)
1227 flags
= "[weak_def] ";
1228 fprintf(stdout
, "0x%08llX %s%s\n", fBaseAddress
+it
->address
, flags
, it
->name
);
1234 template <typename A
>
1235 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1236 const uint8_t* parent
, const uint8_t* p
,
1237 char* cummulativeString
, int curStrOffset
)
1239 const uint8_t* const me
= p
;
1240 const uint8_t terminalSize
= *p
++;
1241 const uint8_t* children
= p
+ terminalSize
;
1242 if ( terminalSize
!= 0 ) {
1243 uint32_t flags
= read_uleb128(p
, end
);
1244 uint64_t address
= read_uleb128(p
, end
);
1245 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1248 printf("\tnode%03ld;\n", (long)(me
-start
));
1250 const uint8_t childrenCount
= *children
++;
1251 const uint8_t* s
= children
;
1252 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1253 const char* edgeName
= (char*)s
;
1255 while (*s
!= '\0') {
1256 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1259 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1260 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1261 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1262 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1266 template <typename A
>
1267 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1269 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1270 printf("no compressed export info\n");
1273 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1274 const uint8_t* end
= &p
[fInfo
->export_size()];
1275 char cummulativeString
[2000];
1276 printf("digraph {\n");
1277 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1286 static void dump(const char* path
)
1288 struct stat stat_buf
;
1291 int fd
= ::open(path
, O_RDONLY
, 0);
1293 throw "cannot open file";
1294 if ( ::fstat(fd
, &stat_buf
) != 0 )
1295 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
1296 uint32_t length
= stat_buf
.st_size
;
1297 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1298 if ( p
== ((uint8_t*)(-1)) )
1299 throw "cannot map file";
1301 const mach_header
* mh
= (mach_header
*)p
;
1302 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1303 const struct fat_header
* fh
= (struct fat_header
*)p
;
1304 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1305 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1306 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1307 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
1308 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
1309 if ( cputype
== (uint32_t)sPreferredArch
) {
1311 case CPU_TYPE_POWERPC
:
1312 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
1313 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
);
1315 throw "in universal file, ppc slice does not contain ppc mach-o";
1318 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
1319 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
);
1321 throw "in universal file, i386 slice does not contain i386 mach-o";
1323 case CPU_TYPE_POWERPC64
:
1324 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
1325 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
);
1327 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
1329 case CPU_TYPE_X86_64
:
1330 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
1331 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
);
1333 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
1336 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
1337 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
);
1339 throw "in universal file, arm slice does not contain arm mach-o";
1342 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
1347 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
1348 DyldInfoPrinter
<x86
>::make(p
, length
, path
);
1350 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
1351 DyldInfoPrinter
<ppc
>::make(p
, length
, path
);
1353 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
1354 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
);
1356 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
1357 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
);
1359 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
1360 DyldInfoPrinter
<arm
>::make(p
, length
, path
);
1363 throw "not a known file type";
1366 catch (const char* msg
) {
1367 throwf("%s in %s", msg
, path
);
1373 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
1374 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
1375 "\t-bind print addresses dyld will set based on symbolic lookups\n"
1376 "\t-weak_bind print symbols which dyld must coalesce\n"
1377 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
1378 "\t-export print addresses of all symbols this file exports\n"
1379 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
1380 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
1385 int main(int argc
, const char* argv
[])
1393 std::vector
<const char*> files
;
1394 for(int i
=1; i
< argc
; ++i
) {
1395 const char* arg
= argv
[i
];
1396 if ( arg
[0] == '-' ) {
1397 if ( strcmp(arg
, "-arch") == 0 ) {
1398 const char* arch
= ++i
<argc
? argv
[i
]: "";
1399 if ( strcmp(arch
, "ppc64") == 0 )
1400 sPreferredArch
= CPU_TYPE_POWERPC64
;
1401 else if ( strcmp(arch
, "ppc") == 0 )
1402 sPreferredArch
= CPU_TYPE_POWERPC
;
1403 else if ( strcmp(arch
, "i386") == 0 )
1404 sPreferredArch
= CPU_TYPE_I386
;
1405 else if ( strcmp(arch
, "x86_64") == 0 )
1406 sPreferredArch
= CPU_TYPE_X86_64
;
1408 throwf("unknown architecture %s", arch
);
1410 else if ( strcmp(arg
, "-rebase") == 0 ) {
1413 else if ( strcmp(arg
, "-bind") == 0 ) {
1416 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
1417 printWeakBind
= true;
1419 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
1420 printLazyBind
= true;
1422 else if ( strcmp(arg
, "-export") == 0 ) {
1425 else if ( strcmp(arg
, "-opcodes") == 0 ) {
1426 printOpcodes
= true;
1428 else if ( strcmp(arg
, "-export_dot") == 0 ) {
1429 printExportGraph
= true;
1432 throwf("unknown option: %s\n", arg
);
1436 files
.push_back(arg
);
1439 if ( files
.size() == 0 )
1441 if ( files
.size() == 1 ) {
1445 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
1446 printf("\n%s:\n", *it
);
1451 catch (const char* msg
) {
1452 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);