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 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
= "??";
742 while ( !done
&& (p
< end
) ) {
743 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
744 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
747 case BIND_OPCODE_DONE
:
750 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
751 libraryOrdinal
= immediate
;
752 fromDylib
= ordinalName(libraryOrdinal
);
754 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
755 libraryOrdinal
= read_uleb128(p
, end
);
756 fromDylib
= ordinalName(libraryOrdinal
);
758 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
759 // the special ordinals are negative numbers
760 if ( immediate
== 0 )
763 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
764 libraryOrdinal
= signExtended
;
766 fromDylib
= ordinalName(libraryOrdinal
);
768 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
769 symbolName
= (char*)p
;
774 case BIND_OPCODE_SET_TYPE_IMM
:
776 typeName
= bindTypeName(type
);
778 case BIND_OPCODE_SET_ADDEND_SLEB
:
779 addend
= read_sleb128(p
, end
);
781 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
782 segIndex
= immediate
;
783 segStartAddr
= segStartAddress(segIndex
);
784 segName
= segmentName(segIndex
);
785 segOffset
= read_uleb128(p
, end
);
787 case BIND_OPCODE_ADD_ADDR_ULEB
:
788 segOffset
+= read_uleb128(p
, end
);
790 case BIND_OPCODE_DO_BIND
:
791 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
);
792 segOffset
+= sizeof(pint_t
);
794 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
795 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
);
796 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
798 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
799 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
);
800 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
802 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
803 count
= read_uleb128(p
, end
);
804 skip
= read_uleb128(p
, end
);
805 for (uint32_t i
=0; i
< count
; ++i
) {
806 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
);
807 segOffset
+= skip
+ sizeof(pint_t
);
811 throwf("bad bind opcode %d", *p
);
818 template <typename A
>
819 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
821 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
822 printf("no weak binding\n");
825 printf("weak binding information:\n");
826 printf("segment section address type addend symbol\n");
827 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
828 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
831 uint8_t segIndex
= 0;
832 uint64_t segOffset
= 0;
833 const char* symbolName
= NULL
;
837 pint_t segStartAddr
= 0;
838 const char* segName
= "??";
839 const char* typeName
= "??";
841 while ( !done
&& (p
< end
) ) {
842 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
843 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
846 case BIND_OPCODE_DONE
:
849 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
850 symbolName
= (char*)p
;
854 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
855 printf(" strong %s\n", symbolName
);
857 case BIND_OPCODE_SET_TYPE_IMM
:
859 typeName
= bindTypeName(type
);
861 case BIND_OPCODE_SET_ADDEND_SLEB
:
862 addend
= read_sleb128(p
, end
);
864 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
865 segIndex
= immediate
;
866 segStartAddr
= segStartAddress(segIndex
);
867 segName
= segmentName(segIndex
);
868 segOffset
= read_uleb128(p
, end
);
870 case BIND_OPCODE_ADD_ADDR_ULEB
:
871 segOffset
+= read_uleb128(p
, end
);
873 case BIND_OPCODE_DO_BIND
:
874 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
875 segOffset
+= sizeof(pint_t
);
877 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
878 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
879 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
881 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
882 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
883 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
885 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
886 count
= read_uleb128(p
, end
);
887 skip
= read_uleb128(p
, end
);
888 for (uint32_t i
=0; i
< count
; ++i
) {
889 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
890 segOffset
+= skip
+ sizeof(pint_t
);
894 throwf("unknown weak bind opcode %d", *p
);
902 template <typename A
>
903 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
905 if ( fInfo
== NULL
) {
906 printf("no compressed dyld info\n");
908 else if ( fInfo
->lazy_bind_off() == 0 ) {
909 printf("no compressed lazy binding info\n");
912 printf("lazy binding information:\n");
913 printf("segment section address index dylib symbol\n");
914 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
915 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
917 uint8_t type
= BIND_TYPE_POINTER
;
918 uint8_t segIndex
= 0;
919 uint64_t segOffset
= 0;
920 const char* symbolName
= NULL
;
921 const char* fromDylib
= "??";
922 int libraryOrdinal
= 0;
924 uint32_t lazy_offset
= 0;
925 pint_t segStartAddr
= 0;
926 const char* segName
= "??";
927 const char* typeName
= "??";
928 for (const uint8_t* p
=start
; p
< end
; ) {
929 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
930 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
933 case BIND_OPCODE_DONE
:
934 lazy_offset
= p
-start
;
936 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
937 libraryOrdinal
= immediate
;
938 fromDylib
= ordinalName(libraryOrdinal
);
940 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
941 libraryOrdinal
= read_uleb128(p
, end
);
942 fromDylib
= ordinalName(libraryOrdinal
);
944 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
945 // the special ordinals are negative numbers
946 if ( immediate
== 0 )
949 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
950 libraryOrdinal
= signExtended
;
952 fromDylib
= ordinalName(libraryOrdinal
);
954 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
955 symbolName
= (char*)p
;
960 case BIND_OPCODE_SET_TYPE_IMM
:
962 typeName
= bindTypeName(type
);
964 case BIND_OPCODE_SET_ADDEND_SLEB
:
965 addend
= read_sleb128(p
, end
);
967 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
968 segIndex
= immediate
;
969 segStartAddr
= segStartAddress(segIndex
);
970 segName
= segmentName(segIndex
);
971 segOffset
= read_uleb128(p
, end
);
973 case BIND_OPCODE_ADD_ADDR_ULEB
:
974 segOffset
+= read_uleb128(p
, end
);
976 case BIND_OPCODE_DO_BIND
:
977 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
);
978 segOffset
+= sizeof(pint_t
);
981 throwf("bad lazy bind opcode %d", *p
);
989 uint8_t type
= BIND_TYPE_POINTER
;
991 uint64_t address
= fBaseAddress
;
992 const char* symbolName
= NULL
;
993 int libraryOrdinal
= 0;
995 uint32_t segmentIndex
= 0;
998 for (const uint8_t* p
= start
; p
< end
; ) {
999 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1000 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1001 uint32_t opcodeOffset
= p
-start
;
1004 case BIND_OPCODE_DONE
:
1005 printf("0x%08X BIND_OPCODE_DONE\n", opcodeOffset
);
1007 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1008 libraryOrdinal
= immediate
;
1009 printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1011 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1012 libraryOrdinal
= read_uleb128(p
, end
);
1013 printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1015 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1016 // the special ordinals are negative numbers
1017 if ( immediate
== 0 )
1020 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1021 libraryOrdinal
= signExtended
;
1023 printf("0x%08X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1025 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1027 symbolName
= (char*)p
;
1031 printf("0x%08X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1033 case BIND_OPCODE_SET_TYPE_IMM
:
1035 printf("0x%08X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1037 case BIND_OPCODE_SET_ADDEND_SLEB
:
1038 addend
= read_sleb128(p
, end
);
1039 printf("0x%08X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1041 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1042 segmentIndex
= immediate
;
1043 address
= read_uleb128(p
, end
);
1044 printf("0x%08X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1046 case BIND_OPCODE_ADD_ADDR_ULEB
:
1047 skip
= read_uleb128(p
, end
);
1048 printf("0x%08X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1050 case BIND_OPCODE_DO_BIND
:
1051 printf("0x%08X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1053 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1054 skip
= read_uleb128(p
, end
);
1055 printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1057 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1058 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1059 printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1061 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1062 count
= read_uleb128(p
, end
);
1063 skip
= read_uleb128(p
, end
);
1064 printf("0x%08X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1067 throwf("unknown bind opcode %d", *p
);
1072 template <typename A
>
1073 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1075 if ( fInfo
== NULL
) {
1076 printf("no compressed dyld info\n");
1078 else if ( fInfo
->lazy_bind_off() == 0 ) {
1079 printf("no compressed lazy binding info\n");
1082 printf("lazy binding opcodes:\n");
1083 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1084 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1085 uint8_t type
= BIND_TYPE_POINTER
;
1087 uint64_t address
= fBaseAddress
;
1088 const char* symbolName
= NULL
;
1089 int libraryOrdinal
= 0;
1091 uint32_t segmentIndex
= 0;
1094 for (const uint8_t* p
= start
; p
< end
; ) {
1095 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1096 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1097 uint32_t opcodeOffset
= p
-start
;
1100 case BIND_OPCODE_DONE
:
1101 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1103 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1104 libraryOrdinal
= immediate
;
1105 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1107 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1108 libraryOrdinal
= read_uleb128(p
, end
);
1109 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1111 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1112 // the special ordinals are negative numbers
1113 if ( immediate
== 0 )
1116 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1117 libraryOrdinal
= signExtended
;
1119 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1121 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1123 symbolName
= (char*)p
;
1127 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1129 case BIND_OPCODE_SET_TYPE_IMM
:
1131 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1133 case BIND_OPCODE_SET_ADDEND_SLEB
:
1134 addend
= read_sleb128(p
, end
);
1135 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1137 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1138 segmentIndex
= immediate
;
1139 address
= read_uleb128(p
, end
);
1140 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1142 case BIND_OPCODE_ADD_ADDR_ULEB
:
1143 skip
= read_uleb128(p
, end
);
1144 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1146 case BIND_OPCODE_DO_BIND
:
1147 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1149 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1150 skip
= read_uleb128(p
, end
);
1151 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1153 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1154 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1155 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1157 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1158 count
= read_uleb128(p
, end
);
1159 skip
= read_uleb128(p
, end
);
1160 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1163 throwf("unknown bind opcode %d", *p
);
1171 template <typename A
>
1172 void DyldInfoPrinter
<A
>::processExportNode(const uint8_t* const start
, const uint8_t* p
, const uint8_t* const end
,
1173 char* cummulativeString
, int curStrOffset
)
1175 const uint8_t terminalSize
= *p
++;
1176 const uint8_t* children
= p
+ terminalSize
;
1177 if ( terminalSize
!= 0 ) {
1178 uint32_t flags
= read_uleb128(p
, end
);
1179 uint64_t address
= read_uleb128(p
, end
);
1180 if ( flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
)
1181 fprintf(stdout
, "0x%08llX [weak_def] %s\n", address
, cummulativeString
);
1183 fprintf(stdout
, "0x%08llX %s\n", address
, cummulativeString
);
1185 const uint8_t childrenCount
= *children
++;
1186 const uint8_t* s
= children
;
1187 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1189 while (*s
!= '\0') {
1190 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1193 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1194 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1195 processExportNode(start
, start
+childNodeOffet
, end
, cummulativeString
, curStrOffset
+edgeStrLen
);
1199 struct SortExportsByAddress
1201 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1203 return ( left
.address
< right
.address
);
1207 template <typename A
>
1208 void DyldInfoPrinter
<A
>::printExportInfo()
1210 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1211 printf("no compressed export info\n");
1214 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1215 const uint8_t* end
= &start
[fInfo
->export_size()];
1216 std::vector
<mach_o::trie::Entry
> list
;
1217 parseTrie(start
, end
, list
);
1218 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1219 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1220 const char* flags
= "";
1221 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
)
1222 flags
= "[weak_def] ";
1223 fprintf(stdout
, "0x%08llX %s%s\n", fBaseAddress
+it
->address
, flags
, it
->name
);
1229 template <typename A
>
1230 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1231 const uint8_t* parent
, const uint8_t* p
,
1232 char* cummulativeString
, int curStrOffset
)
1234 const uint8_t* const me
= p
;
1235 const uint8_t terminalSize
= *p
++;
1236 const uint8_t* children
= p
+ terminalSize
;
1237 if ( terminalSize
!= 0 ) {
1238 uint32_t flags
= read_uleb128(p
, end
);
1239 uint64_t address
= read_uleb128(p
, end
);
1240 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1243 printf("\tnode%03ld;\n", (long)(me
-start
));
1245 const uint8_t childrenCount
= *children
++;
1246 const uint8_t* s
= children
;
1247 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1248 const char* edgeName
= (char*)s
;
1250 while (*s
!= '\0') {
1251 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1254 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1255 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1256 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1257 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1261 template <typename A
>
1262 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1264 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1265 printf("no compressed export info\n");
1268 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1269 const uint8_t* end
= &p
[fInfo
->export_size()];
1270 char cummulativeString
[2000];
1271 printf("digraph {\n");
1272 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1281 static void dump(const char* path
)
1283 struct stat stat_buf
;
1286 int fd
= ::open(path
, O_RDONLY
, 0);
1288 throw "cannot open file";
1289 if ( ::fstat(fd
, &stat_buf
) != 0 )
1290 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
1291 uint32_t length
= stat_buf
.st_size
;
1292 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1293 if ( p
== ((uint8_t*)(-1)) )
1294 throw "cannot map file";
1296 const mach_header
* mh
= (mach_header
*)p
;
1297 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1298 const struct fat_header
* fh
= (struct fat_header
*)p
;
1299 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1300 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1301 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1302 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
1303 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
1304 if ( cputype
== (uint32_t)sPreferredArch
) {
1306 case CPU_TYPE_POWERPC
:
1307 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
1308 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
);
1310 throw "in universal file, ppc slice does not contain ppc mach-o";
1313 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
1314 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
);
1316 throw "in universal file, i386 slice does not contain i386 mach-o";
1318 case CPU_TYPE_POWERPC64
:
1319 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
1320 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
);
1322 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
1324 case CPU_TYPE_X86_64
:
1325 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
1326 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
);
1328 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
1331 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
1332 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
);
1334 throw "in universal file, arm slice does not contain arm mach-o";
1337 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
1342 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
1343 DyldInfoPrinter
<x86
>::make(p
, length
, path
);
1345 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
1346 DyldInfoPrinter
<ppc
>::make(p
, length
, path
);
1348 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
1349 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
);
1351 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
1352 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
);
1354 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
1355 DyldInfoPrinter
<arm
>::make(p
, length
, path
);
1358 throw "not a known file type";
1361 catch (const char* msg
) {
1362 throwf("%s in %s", msg
, path
);
1368 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
1369 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
1370 "\t-bind print addresses dyld will set based on symbolic lookups\n"
1371 "\t-weak_bind print symbols which dyld must coalesce\n"
1372 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
1373 "\t-export print addresses of all symbols this file exports\n"
1374 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
1375 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
1380 int main(int argc
, const char* argv
[])
1388 std::vector
<const char*> files
;
1389 for(int i
=1; i
< argc
; ++i
) {
1390 const char* arg
= argv
[i
];
1391 if ( arg
[0] == '-' ) {
1392 if ( strcmp(arg
, "-arch") == 0 ) {
1393 const char* arch
= ++i
<argc
? argv
[i
]: "";
1394 if ( strcmp(arch
, "ppc64") == 0 )
1395 sPreferredArch
= CPU_TYPE_POWERPC64
;
1396 else if ( strcmp(arch
, "ppc") == 0 )
1397 sPreferredArch
= CPU_TYPE_POWERPC
;
1398 else if ( strcmp(arch
, "i386") == 0 )
1399 sPreferredArch
= CPU_TYPE_I386
;
1400 else if ( strcmp(arch
, "x86_64") == 0 )
1401 sPreferredArch
= CPU_TYPE_X86_64
;
1403 throwf("unknown architecture %s", arch
);
1405 else if ( strcmp(arg
, "-rebase") == 0 ) {
1408 else if ( strcmp(arg
, "-bind") == 0 ) {
1411 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
1412 printWeakBind
= true;
1414 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
1415 printLazyBind
= true;
1417 else if ( strcmp(arg
, "-export") == 0 ) {
1420 else if ( strcmp(arg
, "-opcodes") == 0 ) {
1421 printOpcodes
= true;
1423 else if ( strcmp(arg
, "-export_dot") == 0 ) {
1424 printExportGraph
= true;
1427 throwf("unknown option: %s\n", arg
);
1431 files
.push_back(arg
);
1434 if ( files
.size() == 0 )
1436 if ( files
.size() == 1 ) {
1440 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
1441 printf("\n%s:\n", *it
);
1446 catch (const char* msg
) {
1447 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);