1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2008-2009 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
;
50 static cpu_type_t sPreferredSubArch
= 0;
53 __attribute__((noreturn
))
54 void throwf(const char* format
, ...)
58 va_start(list
, format
);
59 vasprintf(&p
, format
, list
);
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() {}
78 typedef typename
A::P P
;
79 typedef typename
A::P::E E
;
80 typedef typename
A::P::uint_t pint_t
;
85 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
88 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> StringSet
;
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();
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
);
126 const macho_header
<P
>* fHeader
;
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
;
145 bool DyldInfoPrinter
<ppc
>::validFile(const uint8_t* fileContent
)
147 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
148 if ( header
->magic() != MH_MAGIC
)
150 if ( header
->cputype() != CPU_TYPE_POWERPC
)
152 switch (header
->filetype()) {
163 bool DyldInfoPrinter
<ppc64
>::validFile(const uint8_t* fileContent
)
165 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
166 if ( header
->magic() != MH_MAGIC_64
)
168 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
170 switch (header
->filetype()) {
181 bool DyldInfoPrinter
<x86
>::validFile(const uint8_t* fileContent
)
183 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
184 if ( header
->magic() != MH_MAGIC
)
186 if ( header
->cputype() != CPU_TYPE_I386
)
188 switch (header
->filetype()) {
199 bool DyldInfoPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
201 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
202 if ( header
->magic() != MH_MAGIC_64
)
204 if ( header
->cputype() != CPU_TYPE_X86_64
)
206 switch (header
->filetype()) {
217 bool DyldInfoPrinter
<arm
>::validFile(const uint8_t* fileContent
)
219 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
220 if ( header
->magic() != MH_MAGIC
)
222 if ( header
->cputype() != CPU_TYPE_ARM
)
224 switch (header
->filetype()) {
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)
242 if ( ! validFile(fileContent
) )
243 throw "not a mach-o file that can be checked";
245 fPath
= strdup(path
);
246 fHeader
= (const macho_header
<P
>*)fileContent
;
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() ) {
262 case LC_DYLD_INFO_ONLY
:
263 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
265 case macho_segment_command
<P
>::CMD
:
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;
282 case LC_LOAD_WEAK_DYLIB
:
283 case LC_REEXPORT_DYLIB
:
284 case LC_LAZY_LOAD_DYLIB
:
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
);
296 fDylibs
.push_back(leafName
);
301 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
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();
313 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
320 printRelocRebaseInfo();
326 printClassicBindingInfo();
329 printWeakBindingInfo();
330 if ( printLazyBind
) {
332 printLazyBindingInfo();
334 printClassicLazyBindingInfo();
340 printSymbolTableExportInfo();
342 if ( printOpcodes
) {
343 printRebaseInfoOpcodes();
344 printBindingInfoOpcodes(false);
345 printBindingInfoOpcodes(true);
346 printLazyBindingOpcodes();
348 if ( printExportGraph
)
349 printExportInfoGraph();
352 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
358 throwf("malformed uleb128");
360 uint64_t slice
= *p
& 0x7f;
362 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
363 throwf("uleb128 too big");
365 result
|= (slice
<< bit
);
373 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
380 throwf("malformed sleb128");
382 result
|= ((byte
& 0x7f) << bit
);
384 } while (byte
& 0x80);
385 // sign extend negative numbers
386 if ( (byte
& 0x40) != 0 )
387 result
|= (-1LL) << bit
;
392 template <typename A
>
393 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
396 case REBASE_TYPE_POINTER
:
398 case REBASE_TYPE_TEXT_ABSOLUTE32
:
400 case REBASE_TYPE_TEXT_PCREL32
:
403 return "!!unknown!!";
407 template <typename A
>
408 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
411 case BIND_TYPE_POINTER
:
413 case BIND_TYPE_TEXT_ABSOLUTE32
:
415 case BIND_TYPE_TEXT_PCREL32
:
418 return "!!unknown!!";
422 template <typename A
>
423 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
425 if ( segIndex
> fSegments
.size() )
426 throw "segment index out of range";
427 return fSegments
[segIndex
]->vmaddr();
430 template <typename A
>
431 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
433 if ( segIndex
> fSegments
.size() )
434 throw "segment index out of range";
435 return fSegments
[segIndex
]->segname();
438 template <typename A
>
439 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
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
= §ionsStart
[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);
454 return sect
->sectname();
461 template <typename A
>
462 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
464 static char buffer
[64];
465 strcpy(buffer
, segmentName(segIndex
));
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
= §ionsStart
[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);
481 template <typename A
>
482 uint8_t DyldInfoPrinter
<A
>::segmentIndexForAddress(pint_t address
)
484 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
485 if ( (fSegments
[i
]->vmaddr() <= address
) && (address
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
489 throwf("address 0x%llX is not in any segment", (uint64_t)address
);
492 template <typename A
>
493 typename
A::P::uint_t
* DyldInfoPrinter
<A
>::mappedAddressForVMAddress(pint_t vmaddress
)
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
);
501 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress
);
504 template <typename A
>
505 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
507 switch ( libraryOrdinal
) {
508 case BIND_SPECIAL_DYLIB_SELF
:
510 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
511 return "main-executable";
512 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
513 return "flat-namespace";
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];
522 template <typename A
>
523 const char* DyldInfoPrinter
<A
>::classicOrdinalName(int libraryOrdinal
)
525 switch ( libraryOrdinal
) {
526 case SELF_LIBRARY_ORDINAL
:
528 case EXECUTABLE_ORDINAL
:
529 return "main-executable";
530 case DYNAMIC_LOOKUP_ORDINAL
:
531 return "flat-namespace";
533 if ( libraryOrdinal
> (int)fDylibs
.size() )
534 throw "libraryOrdinal out of range";
535 return fDylibs
[libraryOrdinal
-1];
538 template <typename A
>
539 void DyldInfoPrinter
<A
>::printRebaseInfo()
541 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
542 printf("no compressed rebase info\n");
545 printf("rebase information (from compressed dyld info):\n");
546 printf("segment section address type\n");
548 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
549 const uint8_t* end
= &p
[fInfo
->rebase_size()];
552 uint64_t segOffset
= 0;
556 pint_t segStartAddr
= 0;
557 const char* segName
= "??";
558 const char* typeName
= "??";
560 while ( !done
&& (p
< end
) ) {
561 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
562 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
565 case REBASE_OPCODE_DONE
:
568 case REBASE_OPCODE_SET_TYPE_IMM
:
570 typeName
= rebaseTypeName(type
);
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
);
578 case REBASE_OPCODE_ADD_ADDR_ULEB
:
579 segOffset
+= read_uleb128(p
, end
);
581 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
582 segOffset
+= immediate
*sizeof(pint_t
);
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
);
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
);
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
);
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
);
610 throwf("bad rebase opcode %d", *p
);
619 template <typename A
>
620 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
622 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
623 printf("no compressed rebase info\n");
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()];
631 uint64_t address
= fBaseAddress
;
634 unsigned int segmentIndex
;
636 while ( !done
&& (p
< end
) ) {
637 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
638 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
641 case REBASE_OPCODE_DONE
:
643 printf("REBASE_OPCODE_DONE()\n");
645 case REBASE_OPCODE_SET_TYPE_IMM
:
647 printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type
);
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
);
654 case REBASE_OPCODE_ADD_ADDR_ULEB
:
655 address
= read_uleb128(p
, end
);
656 printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address
);
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
);
662 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
663 printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate
);
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
);
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
);
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
);
679 throwf("bad rebase opcode %d", *p
);
691 template <typename A
>
692 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
694 if ( fInfo
== NULL
) {
695 printf("no compressed binding info\n");
697 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
698 printf("no compressed binding info\n");
700 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
701 printf("no compressed weak binding info\n");
704 const uint8_t* start
;
707 printf("weak binding opcodes:\n");
708 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
709 end
= &start
[fInfo
->weak_bind_size()];
712 printf("binding opcodes:\n");
713 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
714 end
= &start
[fInfo
->bind_size()];
716 const uint8_t* p
= start
;
719 uint64_t address
= fBaseAddress
;
720 const char* symbolName
= NULL
;
721 int libraryOrdinal
= 0;
723 uint32_t segmentIndex
= 0;
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
;
733 case BIND_OPCODE_DONE
:
735 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
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
);
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
);
745 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
746 // the special ordinals are negative numbers
747 if ( immediate
== 0 )
750 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
751 libraryOrdinal
= signExtended
;
753 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
755 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
757 symbolName
= (char*)p
;
761 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
763 case BIND_OPCODE_SET_TYPE_IMM
:
765 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
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
);
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
);
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
);
780 case BIND_OPCODE_DO_BIND
:
781 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
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
);
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
);
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
);
797 throwf("unknown bind opcode %d", *p
);
806 template <typename A
>
807 void DyldInfoPrinter
<A
>::printBindingInfo()
809 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
810 printf("no compressed binding info\n");
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()];
819 uint8_t segIndex
= 0;
820 uint64_t segOffset
= 0;
821 const char* symbolName
= NULL
;
822 const char* fromDylib
= "??";
823 int libraryOrdinal
= 0;
827 pint_t segStartAddr
= 0;
828 const char* segName
= "??";
829 const char* typeName
= "??";
830 const char* weak_import
= "";
832 while ( !done
&& (p
< end
) ) {
833 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
834 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
837 case BIND_OPCODE_DONE
:
840 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
841 libraryOrdinal
= immediate
;
842 fromDylib
= ordinalName(libraryOrdinal
);
844 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
845 libraryOrdinal
= read_uleb128(p
, end
);
846 fromDylib
= ordinalName(libraryOrdinal
);
848 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
849 // the special ordinals are negative numbers
850 if ( immediate
== 0 )
853 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
854 libraryOrdinal
= signExtended
;
856 fromDylib
= ordinalName(libraryOrdinal
);
858 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
859 symbolName
= (char*)p
;
863 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
864 weak_import
= "weak";
868 case BIND_OPCODE_SET_TYPE_IMM
:
870 typeName
= bindTypeName(type
);
872 case BIND_OPCODE_SET_ADDEND_SLEB
:
873 addend
= read_sleb128(p
, end
);
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
);
881 case BIND_OPCODE_ADD_ADDR_ULEB
:
882 segOffset
+= read_uleb128(p
, end
);
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
);
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
);
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
);
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
);
905 throwf("bad bind opcode %d", *p
);
912 template <typename A
>
913 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
915 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
916 printf("no weak binding\n");
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()];
925 uint8_t segIndex
= 0;
926 uint64_t segOffset
= 0;
927 const char* symbolName
= NULL
;
931 pint_t segStartAddr
= 0;
932 const char* segName
= "??";
933 const char* typeName
= "??";
935 while ( !done
&& (p
< end
) ) {
936 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
937 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
940 case BIND_OPCODE_DONE
:
943 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
944 symbolName
= (char*)p
;
948 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
949 printf(" strong %s\n", symbolName
);
951 case BIND_OPCODE_SET_TYPE_IMM
:
953 typeName
= bindTypeName(type
);
955 case BIND_OPCODE_SET_ADDEND_SLEB
:
956 addend
= read_sleb128(p
, end
);
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
);
964 case BIND_OPCODE_ADD_ADDR_ULEB
:
965 segOffset
+= read_uleb128(p
, end
);
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
);
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
);
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
);
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
);
988 throwf("unknown weak bind opcode %d", *p
);
996 template <typename A
>
997 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
999 if ( fInfo
== NULL
) {
1000 printf("no compressed dyld info\n");
1002 else if ( fInfo
->lazy_bind_off() == 0 ) {
1003 printf("no compressed lazy binding info\n");
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()];
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;
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
;
1027 case BIND_OPCODE_DONE
:
1028 lazy_offset
= p
-start
;
1030 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1031 libraryOrdinal
= immediate
;
1032 fromDylib
= ordinalName(libraryOrdinal
);
1034 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1035 libraryOrdinal
= read_uleb128(p
, end
);
1036 fromDylib
= ordinalName(libraryOrdinal
);
1038 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1039 // the special ordinals are negative numbers
1040 if ( immediate
== 0 )
1043 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1044 libraryOrdinal
= signExtended
;
1046 fromDylib
= ordinalName(libraryOrdinal
);
1048 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1049 symbolName
= (char*)p
;
1054 case BIND_OPCODE_SET_TYPE_IMM
:
1056 typeName
= bindTypeName(type
);
1058 case BIND_OPCODE_SET_ADDEND_SLEB
:
1059 addend
= read_sleb128(p
, end
);
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
);
1067 case BIND_OPCODE_ADD_ADDR_ULEB
:
1068 segOffset
+= read_uleb128(p
, end
);
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
);
1075 throwf("bad lazy bind opcode %d", *p
);
1082 template <typename A
>
1083 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1085 if ( fInfo
== NULL
) {
1086 printf("no compressed dyld info\n");
1088 else if ( fInfo
->lazy_bind_off() == 0 ) {
1089 printf("no compressed lazy binding info\n");
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
;
1097 uint64_t address
= fBaseAddress
;
1098 const char* symbolName
= NULL
;
1099 int libraryOrdinal
= 0;
1101 uint32_t segmentIndex
= 0;
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
;
1110 case BIND_OPCODE_DONE
:
1111 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
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
);
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
);
1121 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1122 // the special ordinals are negative numbers
1123 if ( immediate
== 0 )
1126 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1127 libraryOrdinal
= signExtended
;
1129 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1131 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1133 symbolName
= (char*)p
;
1137 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1139 case BIND_OPCODE_SET_TYPE_IMM
:
1141 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
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
);
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
);
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
);
1156 case BIND_OPCODE_DO_BIND
:
1157 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
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
);
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
);
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
);
1173 throwf("unknown bind opcode %d", *p
);
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
)
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
);
1193 fprintf(stdout
, "0x%08llX %s\n", address
, cummulativeString
);
1195 const uint8_t childrenCount
= *children
++;
1196 const uint8_t* s
= children
;
1197 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1199 while (*s
!= '\0') {
1200 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1203 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1204 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1205 processExportNode(start
, start
+childNodeOffet
, end
, cummulativeString
, curStrOffset
+edgeStrLen
);
1209 struct SortExportsByAddress
1211 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1213 return ( left
.address
< right
.address
);
1217 template <typename A
>
1218 void DyldInfoPrinter
<A
>::printExportInfo()
1220 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1221 printf("no compressed export info\n");
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
);
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
)
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
);
1255 printf("\tnode%03ld;\n", (long)(me
-start
));
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
;
1262 while (*s
!= '\0') {
1263 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
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
);
1273 template <typename A
>
1274 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1276 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1277 printf("no compressed export info\n");
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);
1291 ppc::P::uint_t DyldInfoPrinter
<ppc
>::relocBase()
1293 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1294 return fFirstWritableSegment
->vmaddr();
1296 return fFirstSegment
->vmaddr();
1300 ppc64::P::uint_t DyldInfoPrinter
<ppc64
>::relocBase()
1302 if ( fWriteableSegmentWithAddrOver4G
)
1303 return fFirstWritableSegment
->vmaddr();
1305 return fFirstSegment
->vmaddr();
1309 x86::P::uint_t DyldInfoPrinter
<x86
>::relocBase()
1311 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1312 return fFirstWritableSegment
->vmaddr();
1314 return fFirstSegment
->vmaddr();
1318 x86_64::P::uint_t DyldInfoPrinter
<x86_64
>::relocBase()
1320 // check for split-seg
1321 return fFirstWritableSegment
->vmaddr();
1325 arm::P::uint_t DyldInfoPrinter
<arm
>::relocBase()
1327 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1328 return fFirstWritableSegment
->vmaddr();
1330 return fFirstSegment
->vmaddr();
1335 const char* DyldInfoPrinter
<ppc
>::relocTypeName(uint8_t r_type
)
1337 if ( r_type
== GENERIC_RELOC_VANILLA
)
1339 else if ( r_type
== PPC_RELOC_PB_LA_PTR
)
1340 return "pb pointer";
1346 const char* DyldInfoPrinter
<ppc64
>::relocTypeName(uint8_t r_type
)
1348 if ( r_type
== GENERIC_RELOC_VANILLA
)
1355 const char* DyldInfoPrinter
<x86
>::relocTypeName(uint8_t r_type
)
1357 if ( r_type
== GENERIC_RELOC_VANILLA
)
1359 else if ( r_type
== GENERIC_RELOC_PB_LA_PTR
)
1360 return "pb pointer";
1366 const char* DyldInfoPrinter
<x86_64
>::relocTypeName(uint8_t r_type
)
1368 if ( r_type
== X86_64_RELOC_UNSIGNED
)
1375 const char* DyldInfoPrinter
<arm
>::relocTypeName(uint8_t r_type
)
1377 if ( r_type
== ARM_RELOC_VANILLA
)
1379 else if ( r_type
== ARM_RELOC_PB_LA_PTR
)
1380 return "pb pointer";
1386 template <typename A
>
1387 void DyldInfoPrinter
<A
>::printRelocRebaseInfo()
1389 if ( fDynamicSymbolTable
== NULL
) {
1390 printf("no classic dynamic symbol table");
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
);
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
);
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
= §ionsStart
[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
);
1447 template <typename A
>
1448 void DyldInfoPrinter
<A
>::printSymbolTableExportInfo()
1450 if ( fDynamicSymbolTable
== NULL
) {
1451 printf("no classic dynamic symbol table");
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] ";
1461 if ( sym
->n_desc() & N_ARM_THUMB_DEF
)
1463 printf("0x%08llX %s%s\n", sym
->n_value()+thumb
, flags
, &fStrings
[sym
->n_strx()]);
1469 template <typename A
>
1470 void DyldInfoPrinter
<A
>::printClassicBindingInfo()
1472 if ( fDynamicSymbolTable
== NULL
) {
1473 printf("no classic dynamic symbol table");
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();
1500 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1501 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
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
= §ionsStart
[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
);
1527 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1528 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
1538 template <typename A
>
1539 void DyldInfoPrinter
<A
>::printClassicLazyBindingInfo()
1541 if ( fDynamicSymbolTable
== NULL
) {
1542 printf("no classic dynamic symbol table");
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
= §ionsStart
[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
);
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
);
1592 static void dump(const char* path
)
1594 struct stat stat_buf
;
1597 int fd
= ::open(path
, O_RDONLY
, 0);
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";
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
)) ) {
1619 case CPU_TYPE_POWERPC
:
1620 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
1621 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
);
1623 throw "in universal file, ppc slice does not contain ppc mach-o";
1626 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
1627 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
);
1629 throw "in universal file, i386 slice does not contain i386 mach-o";
1631 case CPU_TYPE_POWERPC64
:
1632 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
1633 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
);
1635 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
1637 case CPU_TYPE_X86_64
:
1638 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
1639 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
);
1641 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
1644 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
1645 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
);
1647 throw "in universal file, arm slice does not contain arm mach-o";
1650 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
1655 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
1656 DyldInfoPrinter
<x86
>::make(p
, length
, path
);
1658 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
1659 DyldInfoPrinter
<ppc
>::make(p
, length
, path
);
1661 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
1662 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
);
1664 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
1665 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
);
1667 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
1668 DyldInfoPrinter
<arm
>::make(p
, length
, path
);
1671 throw "not a known file type";
1674 catch (const char* msg
) {
1675 throwf("%s in %s", msg
, path
);
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"
1693 int main(int argc
, const char* argv
[])
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
;
1721 else if ( strcmp(arch
, "armv5") == 0 ) {
1722 sPreferredArch
= CPU_TYPE_ARM
;
1723 sPreferredSubArch
= CPU_SUBTYPE_ARM_V5TEJ
;
1725 else if ( strcmp(arch
, "armv6") == 0 ) {
1726 sPreferredArch
= CPU_TYPE_ARM
;
1727 sPreferredSubArch
= CPU_SUBTYPE_ARM_V6
;
1729 else if ( strcmp(arch
, "armv7") == 0 ) {
1730 sPreferredArch
= CPU_TYPE_ARM
;
1731 sPreferredSubArch
= CPU_SUBTYPE_ARM_V7
;
1734 throwf("unknown architecture %s", arch
);
1736 else if ( strcmp(arg
, "-rebase") == 0 ) {
1739 else if ( strcmp(arg
, "-bind") == 0 ) {
1742 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
1743 printWeakBind
= true;
1745 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
1746 printLazyBind
= true;
1748 else if ( strcmp(arg
, "-export") == 0 ) {
1751 else if ( strcmp(arg
, "-opcodes") == 0 ) {
1752 printOpcodes
= true;
1754 else if ( strcmp(arg
, "-export_dot") == 0 ) {
1755 printExportGraph
= true;
1758 throwf("unknown option: %s\n", arg
);
1762 files
.push_back(arg
);
1765 if ( files
.size() == 0 )
1767 if ( files
.size() == 1 ) {
1771 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
1772 printf("\n%s:\n", *it
);
1777 catch (const char* msg
) {
1778 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);