1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2008-2010 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 bool printExportNodes
= false;
50 static bool printSharedRegion
= false;
51 static bool printFunctionStarts
= false;
52 static bool printDylibs
= false;
53 static cpu_type_t sPreferredArch
= 0;
54 static cpu_type_t sPreferredSubArch
= 0;
57 __attribute__((noreturn
))
58 static void throwf(const char* format
, ...)
62 va_start(list
, format
);
63 vasprintf(&p
, format
, list
);
75 static bool validFile(const uint8_t* fileContent
);
76 static DyldInfoPrinter
<A
>* make(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
77 { return new DyldInfoPrinter
<A
>(fileContent
, fileLength
, path
, printArch
); }
78 virtual ~DyldInfoPrinter() {}
82 typedef typename
A::P P
;
83 typedef typename
A::P::E E
;
84 typedef typename
A::P::uint_t pint_t
;
89 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
92 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> StringSet
;
94 DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
);
95 void printRebaseInfo();
96 void printRebaseInfoOpcodes();
97 void printBindingInfo();
98 void printWeakBindingInfo();
99 void printLazyBindingInfo();
100 void printBindingInfoOpcodes(bool weakBinding
);
101 void printWeakBindingInfoOpcodes();
102 void printLazyBindingOpcodes();
103 void printExportInfo();
104 void printExportInfoGraph();
105 void printExportInfoNodes();
106 void printRelocRebaseInfo();
107 void printSymbolTableExportInfo();
108 void printClassicLazyBindingInfo();
109 void printClassicBindingInfo();
110 void printSharedRegionInfo();
111 void printFunctionStartsInfo();
112 void printDylibsInfo();
113 void printFunctionStartLine(uint64_t addr
);
114 const uint8_t* printSharedRegionInfoForEachULEB128Address(const uint8_t* p
, uint8_t kind
);
116 const char* relocTypeName(uint8_t r_type
);
117 uint8_t segmentIndexForAddress(pint_t addr
);
118 void processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
119 const uint8_t* parent
, const uint8_t* p
,
120 char* cummulativeString
, int curStrOffset
);
121 void gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
122 const uint8_t* parent
, const uint8_t* p
,
123 std::vector
<uint32_t>& nodeStarts
);
124 const char* rebaseTypeName(uint8_t type
);
125 const char* bindTypeName(uint8_t type
);
126 pint_t
segStartAddress(uint8_t segIndex
);
127 const char* segmentName(uint8_t segIndex
);
128 const char* sectionName(uint8_t segIndex
, pint_t address
);
129 const char* getSegAndSectName(uint8_t segIndex
, pint_t address
);
130 const char* ordinalName(int libraryOrdinal
);
131 const char* classicOrdinalName(int libraryOrdinal
);
132 pint_t
* mappedAddressForVMAddress(pint_t vmaddress
);
133 const char* symbolNameForAddress(uint64_t);
137 const macho_header
<P
>* fHeader
;
139 const char* fStrings
;
140 const char* fStringsEnd
;
141 const macho_nlist
<P
>* fSymbols
;
142 uint32_t fSymbolCount
;
143 const macho_dyld_info_command
<P
>* fInfo
;
144 const macho_linkedit_data_command
<P
>* fSharedRegionInfo
;
145 const macho_linkedit_data_command
<P
>* fFunctionStartsInfo
;
146 uint64_t fBaseAddress
;
147 const macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
148 const macho_segment_command
<P
>* fFirstSegment
;
149 const macho_segment_command
<P
>* fFirstWritableSegment
;
150 bool fWriteableSegmentWithAddrOver4G
;
151 std::vector
<const macho_segment_command
<P
>*>fSegments
;
152 std::vector
<const char*> fDylibs
;
153 std::vector
<const macho_dylib_command
<P
>*> fDylibLoadCommands
;
159 bool DyldInfoPrinter
<ppc
>::validFile(const uint8_t* fileContent
)
161 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
162 if ( header
->magic() != MH_MAGIC
)
164 if ( header
->cputype() != CPU_TYPE_POWERPC
)
166 switch (header
->filetype()) {
177 bool DyldInfoPrinter
<ppc64
>::validFile(const uint8_t* fileContent
)
179 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
180 if ( header
->magic() != MH_MAGIC_64
)
182 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
184 switch (header
->filetype()) {
195 bool DyldInfoPrinter
<x86
>::validFile(const uint8_t* fileContent
)
197 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
198 if ( header
->magic() != MH_MAGIC
)
200 if ( header
->cputype() != CPU_TYPE_I386
)
202 switch (header
->filetype()) {
213 bool DyldInfoPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
215 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
216 if ( header
->magic() != MH_MAGIC_64
)
218 if ( header
->cputype() != CPU_TYPE_X86_64
)
220 switch (header
->filetype()) {
231 bool DyldInfoPrinter
<arm
>::validFile(const uint8_t* fileContent
)
233 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
234 if ( header
->magic() != MH_MAGIC
)
236 if ( header
->cputype() != CPU_TYPE_ARM
)
238 switch (header
->filetype()) {
248 template <typename A
>
249 DyldInfoPrinter
<A
>::DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
250 : fHeader(NULL
), fLength(fileLength
),
251 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fInfo(NULL
),
252 fSharedRegionInfo(NULL
), fFunctionStartsInfo(NULL
),
253 fBaseAddress(0), fDynamicSymbolTable(NULL
), fFirstSegment(NULL
), fFirstWritableSegment(NULL
),
254 fWriteableSegmentWithAddrOver4G(false)
257 if ( ! validFile(fileContent
) )
258 throw "not a mach-o file that can be checked";
260 fPath
= strdup(path
);
261 fHeader
= (const macho_header
<P
>*)fileContent
;
264 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
265 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
266 const uint32_t cmd_count
= fHeader
->ncmds();
267 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
268 const macho_load_command
<P
>* cmd
= cmds
;
269 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
270 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
271 if ( endOfCmd
> endOfLoadCommands
)
272 throwf("load command #%d extends beyond the end of the load commands", i
);
273 if ( endOfCmd
> endOfFile
)
274 throwf("load command #%d extends beyond the end of the file", i
);
275 switch ( cmd
->cmd() ) {
277 case LC_DYLD_INFO_ONLY
:
278 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
280 case macho_segment_command
<P
>::CMD
:
282 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
283 fSegments
.push_back(segCmd
);
284 if ( (segCmd
->fileoff() == 0) && (segCmd
->filesize() != 0) )
285 fBaseAddress
= segCmd
->vmaddr();
286 if ( fFirstSegment
== NULL
)
287 fFirstSegment
= segCmd
;
288 if ( (segCmd
->initprot() & VM_PROT_WRITE
) != 0 ) {
289 if ( fFirstWritableSegment
== NULL
)
290 fFirstWritableSegment
= segCmd
;
291 if ( segCmd
->vmaddr() > 0x100000000ULL
)
292 fWriteableSegmentWithAddrOver4G
= true;
297 case LC_LOAD_WEAK_DYLIB
:
298 case LC_REEXPORT_DYLIB
:
299 case LC_LOAD_UPWARD_DYLIB
:
300 case LC_LAZY_LOAD_DYLIB
:
302 const macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
303 fDylibLoadCommands
.push_back(dylib
);
304 const char* lastSlash
= strrchr(dylib
->name(), '/');
305 const char* leafName
= (lastSlash
!= NULL
) ? lastSlash
+1 : dylib
->name();
306 const char* firstDot
= strchr(leafName
, '.');
307 if ( firstDot
!= NULL
) {
308 char* t
= strdup(leafName
);
309 t
[firstDot
-leafName
] = '\0';
310 fDylibs
.push_back(t
);
313 fDylibs
.push_back(leafName
);
318 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
322 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
323 fSymbolCount
= symtab
->nsyms();
324 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
325 fStrings
= (char*)fHeader
+ symtab
->stroff();
326 fStringsEnd
= fStrings
+ symtab
->strsize();
329 case LC_SEGMENT_SPLIT_INFO
:
330 fSharedRegionInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
332 case LC_FUNCTION_STARTS
:
333 fFunctionStartsInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
336 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
340 switch ( fHeader
->cputype() ) {
342 printf("for arch i386:\n");
344 case CPU_TYPE_X86_64
:
345 printf("for arch x86_64:\n");
347 case CPU_TYPE_POWERPC
:
348 printf("for arch ppc:\n");
351 for (const ARMSubType
* t
=ARMSubTypes
; t
->subTypeName
!= NULL
; ++t
) {
352 if ( (cpu_subtype_t
)fHeader
->cpusubtype() == t
->subType
) {
353 printf("for arch %s:\n", t
->subTypeName
);
365 printRelocRebaseInfo();
371 printClassicBindingInfo();
374 printWeakBindingInfo();
375 if ( printLazyBind
) {
377 printLazyBindingInfo();
379 printClassicLazyBindingInfo();
385 printSymbolTableExportInfo();
387 if ( printOpcodes
) {
388 printRebaseInfoOpcodes();
389 printBindingInfoOpcodes(false);
390 printBindingInfoOpcodes(true);
391 printLazyBindingOpcodes();
393 if ( printExportGraph
)
394 printExportInfoGraph();
395 if ( printExportNodes
)
396 printExportInfoNodes();
397 if ( printSharedRegion
)
398 printSharedRegionInfo();
399 if ( printFunctionStarts
)
400 printFunctionStartsInfo();
405 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
411 throwf("malformed uleb128");
413 uint64_t slice
= *p
& 0x7f;
415 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
416 throwf("uleb128 too big");
418 result
|= (slice
<< bit
);
426 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
433 throwf("malformed sleb128");
435 result
|= ((byte
& 0x7f) << bit
);
437 } while (byte
& 0x80);
438 // sign extend negative numbers
439 if ( (byte
& 0x40) != 0 )
440 result
|= (-1LL) << bit
;
445 template <typename A
>
446 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
449 case REBASE_TYPE_POINTER
:
451 case REBASE_TYPE_TEXT_ABSOLUTE32
:
453 case REBASE_TYPE_TEXT_PCREL32
:
456 return "!!unknown!!";
460 template <typename A
>
461 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
464 case BIND_TYPE_POINTER
:
466 case BIND_TYPE_TEXT_ABSOLUTE32
:
468 case BIND_TYPE_TEXT_PCREL32
:
471 return "!!unknown!!";
475 template <typename A
>
476 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
478 if ( segIndex
> fSegments
.size() )
479 throw "segment index out of range";
480 return fSegments
[segIndex
]->vmaddr();
483 template <typename A
>
484 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
486 if ( segIndex
> fSegments
.size() )
487 throw "segment index out of range";
488 return fSegments
[segIndex
]->segname();
491 template <typename A
>
492 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
494 if ( segIndex
> fSegments
.size() )
495 throw "segment index out of range";
496 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
497 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
498 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
499 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
500 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
501 if ( strlen(sect
->sectname()) > 15 ) {
502 static char temp
[18];
503 strlcpy(temp
, sect
->sectname(), 17);
507 return sect
->sectname();
514 template <typename A
>
515 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
517 static char buffer
[64];
518 strcpy(buffer
, segmentName(segIndex
));
520 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
521 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
522 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
523 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
524 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
525 // section name may not be zero terminated
526 char* end
= &buffer
[strlen(buffer
)];
527 strlcpy(end
, sect
->sectname(), 16);
534 template <typename A
>
535 uint8_t DyldInfoPrinter
<A
>::segmentIndexForAddress(pint_t address
)
537 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
538 if ( (fSegments
[i
]->vmaddr() <= address
) && (address
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
542 throwf("address 0x%llX is not in any segment", (uint64_t)address
);
545 template <typename A
>
546 typename
A::P::uint_t
* DyldInfoPrinter
<A
>::mappedAddressForVMAddress(pint_t vmaddress
)
548 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
549 if ( (fSegments
[i
]->vmaddr() <= vmaddress
) && (vmaddress
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
550 unsigned long offsetInMappedFile
= fSegments
[i
]->fileoff()+vmaddress
-fSegments
[i
]->vmaddr();
551 return (pint_t
*)((uint8_t*)fHeader
+ offsetInMappedFile
);
554 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress
);
557 template <typename A
>
558 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
560 switch ( libraryOrdinal
) {
561 case BIND_SPECIAL_DYLIB_SELF
:
563 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
564 return "main-executable";
565 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
566 return "flat-namespace";
568 if ( libraryOrdinal
< BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
569 throw "unknown special ordinal";
570 if ( libraryOrdinal
> (int)fDylibs
.size() )
571 throw "libraryOrdinal out of range";
572 return fDylibs
[libraryOrdinal
-1];
575 template <typename A
>
576 const char* DyldInfoPrinter
<A
>::classicOrdinalName(int libraryOrdinal
)
578 if ( (fHeader
->flags() & MH_TWOLEVEL
) == 0 )
579 return "flat-namespace";
580 switch ( libraryOrdinal
) {
581 case SELF_LIBRARY_ORDINAL
:
583 case EXECUTABLE_ORDINAL
:
584 return "main-executable";
585 case DYNAMIC_LOOKUP_ORDINAL
:
586 return "flat-namespace";
588 if ( libraryOrdinal
> (int)fDylibs
.size() )
589 throw "libraryOrdinal out of range";
590 return fDylibs
[libraryOrdinal
-1];
593 template <typename A
>
594 void DyldInfoPrinter
<A
>::printRebaseInfo()
596 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
597 printf("no compressed rebase info\n");
600 printf("rebase information (from compressed dyld info):\n");
601 printf("segment section address type\n");
603 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
604 const uint8_t* end
= &p
[fInfo
->rebase_size()];
607 uint64_t segOffset
= 0;
611 pint_t segStartAddr
= 0;
612 const char* segName
= "??";
613 const char* typeName
= "??";
615 while ( !done
&& (p
< end
) ) {
616 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
617 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
620 case REBASE_OPCODE_DONE
:
623 case REBASE_OPCODE_SET_TYPE_IMM
:
625 typeName
= rebaseTypeName(type
);
627 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
628 segIndex
= immediate
;
629 segStartAddr
= segStartAddress(segIndex
);
630 segName
= segmentName(segIndex
);
631 segOffset
= read_uleb128(p
, end
);
633 case REBASE_OPCODE_ADD_ADDR_ULEB
:
634 segOffset
+= read_uleb128(p
, end
);
636 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
637 segOffset
+= immediate
*sizeof(pint_t
);
639 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
640 for (int i
=0; i
< immediate
; ++i
) {
641 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
642 segOffset
+= sizeof(pint_t
);
645 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
646 count
= read_uleb128(p
, end
);
647 for (uint32_t i
=0; i
< count
; ++i
) {
648 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
649 segOffset
+= sizeof(pint_t
);
652 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
653 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
654 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
656 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
657 count
= read_uleb128(p
, end
);
658 skip
= read_uleb128(p
, end
);
659 for (uint32_t i
=0; i
< count
; ++i
) {
660 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
661 segOffset
+= skip
+ sizeof(pint_t
);
665 throwf("bad rebase opcode %d", *p
);
674 template <typename A
>
675 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
677 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
678 printf("no compressed rebase info\n");
681 printf("rebase opcodes:\n");
682 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
683 const uint8_t* end
= &p
[fInfo
->rebase_size()];
686 uint64_t address
= fBaseAddress
;
689 unsigned int segmentIndex
;
691 while ( !done
&& (p
< end
) ) {
692 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
693 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
696 case REBASE_OPCODE_DONE
:
698 printf("REBASE_OPCODE_DONE()\n");
700 case REBASE_OPCODE_SET_TYPE_IMM
:
702 printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type
);
704 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
705 segmentIndex
= immediate
;
706 address
= read_uleb128(p
, end
);
707 printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex
, address
);
709 case REBASE_OPCODE_ADD_ADDR_ULEB
:
710 address
= read_uleb128(p
, end
);
711 printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address
);
713 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
714 address
= immediate
*sizeof(pint_t
);
715 printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address
);
717 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
718 printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate
);
720 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
721 count
= read_uleb128(p
, end
);
722 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count
);
724 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
725 skip
= read_uleb128(p
, end
) + sizeof(pint_t
);
726 printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip
);
728 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
729 count
= read_uleb128(p
, end
);
730 skip
= read_uleb128(p
, end
);
731 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count
, skip
);
734 throwf("bad rebase opcode %d", *p
);
746 template <typename A
>
747 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
749 if ( fInfo
== NULL
) {
750 printf("no compressed binding info\n");
752 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
753 printf("no compressed binding info\n");
755 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
756 printf("no compressed weak binding info\n");
759 const uint8_t* start
;
762 printf("weak binding opcodes:\n");
763 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
764 end
= &start
[fInfo
->weak_bind_size()];
767 printf("binding opcodes:\n");
768 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
769 end
= &start
[fInfo
->bind_size()];
771 const uint8_t* p
= start
;
774 uint64_t address
= fBaseAddress
;
775 const char* symbolName
= NULL
;
776 int libraryOrdinal
= 0;
778 uint32_t segmentIndex
= 0;
782 while ( !done
&& (p
< end
) ) {
783 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
784 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
785 uint32_t opcodeOffset
= p
-start
;
788 case BIND_OPCODE_DONE
:
790 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
792 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
793 libraryOrdinal
= immediate
;
794 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
796 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
797 libraryOrdinal
= read_uleb128(p
, end
);
798 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
800 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
801 // the special ordinals are negative numbers
802 if ( immediate
== 0 )
805 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
806 libraryOrdinal
= signExtended
;
808 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
810 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
812 symbolName
= (char*)p
;
816 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
818 case BIND_OPCODE_SET_TYPE_IMM
:
820 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
822 case BIND_OPCODE_SET_ADDEND_SLEB
:
823 addend
= read_sleb128(p
, end
);
824 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
826 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
827 segmentIndex
= immediate
;
828 address
= read_uleb128(p
, end
);
829 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
831 case BIND_OPCODE_ADD_ADDR_ULEB
:
832 skip
= read_uleb128(p
, end
);
833 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
835 case BIND_OPCODE_DO_BIND
:
836 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
838 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
839 skip
= read_uleb128(p
, end
);
840 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
842 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
843 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
844 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
846 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
847 count
= read_uleb128(p
, end
);
848 skip
= read_uleb128(p
, end
);
849 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
852 throwf("unknown bind opcode %d", *p
);
861 template <typename A
>
862 void DyldInfoPrinter
<A
>::printBindingInfo()
864 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
865 printf("no compressed binding info\n");
868 printf("bind information:\n");
869 printf("segment section address type addend dylib symbol\n");
870 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->bind_off();
871 const uint8_t* end
= &p
[fInfo
->bind_size()];
874 uint8_t segIndex
= 0;
875 uint64_t segOffset
= 0;
876 const char* symbolName
= NULL
;
877 const char* fromDylib
= "??";
878 int libraryOrdinal
= 0;
882 pint_t segStartAddr
= 0;
883 const char* segName
= "??";
884 const char* typeName
= "??";
885 const char* weak_import
= "";
887 while ( !done
&& (p
< end
) ) {
888 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
889 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
892 case BIND_OPCODE_DONE
:
895 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
896 libraryOrdinal
= immediate
;
897 fromDylib
= ordinalName(libraryOrdinal
);
899 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
900 libraryOrdinal
= read_uleb128(p
, end
);
901 fromDylib
= ordinalName(libraryOrdinal
);
903 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
904 // the special ordinals are negative numbers
905 if ( immediate
== 0 )
908 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
909 libraryOrdinal
= signExtended
;
911 fromDylib
= ordinalName(libraryOrdinal
);
913 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
914 symbolName
= (char*)p
;
918 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
919 weak_import
= " (weak import)";
923 case BIND_OPCODE_SET_TYPE_IMM
:
925 typeName
= bindTypeName(type
);
927 case BIND_OPCODE_SET_ADDEND_SLEB
:
928 addend
= read_sleb128(p
, end
);
930 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
931 segIndex
= immediate
;
932 segStartAddr
= segStartAddress(segIndex
);
933 segName
= segmentName(segIndex
);
934 segOffset
= read_uleb128(p
, end
);
936 case BIND_OPCODE_ADD_ADDR_ULEB
:
937 segOffset
+= read_uleb128(p
, end
);
939 case BIND_OPCODE_DO_BIND
:
940 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
941 segOffset
+= sizeof(pint_t
);
943 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
944 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
945 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
947 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
948 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
949 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
951 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
952 count
= read_uleb128(p
, end
);
953 skip
= read_uleb128(p
, end
);
954 for (uint32_t i
=0; i
< count
; ++i
) {
955 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
956 segOffset
+= skip
+ sizeof(pint_t
);
960 throwf("bad bind opcode %d", *p
);
967 template <typename A
>
968 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
970 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
971 printf("no weak binding\n");
974 printf("weak binding information:\n");
975 printf("segment section address type addend symbol\n");
976 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
977 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
980 uint8_t segIndex
= 0;
981 uint64_t segOffset
= 0;
982 const char* symbolName
= NULL
;
986 pint_t segStartAddr
= 0;
987 const char* segName
= "??";
988 const char* typeName
= "??";
990 while ( !done
&& (p
< end
) ) {
991 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
992 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
995 case BIND_OPCODE_DONE
:
998 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
999 symbolName
= (char*)p
;
1003 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
1004 printf(" strong %s\n", symbolName
);
1006 case BIND_OPCODE_SET_TYPE_IMM
:
1008 typeName
= bindTypeName(type
);
1010 case BIND_OPCODE_SET_ADDEND_SLEB
:
1011 addend
= read_sleb128(p
, end
);
1013 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1014 segIndex
= immediate
;
1015 segStartAddr
= segStartAddress(segIndex
);
1016 segName
= segmentName(segIndex
);
1017 segOffset
= read_uleb128(p
, end
);
1019 case BIND_OPCODE_ADD_ADDR_ULEB
:
1020 segOffset
+= read_uleb128(p
, end
);
1022 case BIND_OPCODE_DO_BIND
:
1023 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1024 segOffset
+= sizeof(pint_t
);
1026 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1027 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1028 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1030 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1031 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1032 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1034 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1035 count
= read_uleb128(p
, end
);
1036 skip
= read_uleb128(p
, end
);
1037 for (uint32_t i
=0; i
< count
; ++i
) {
1038 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1039 segOffset
+= skip
+ sizeof(pint_t
);
1043 throwf("unknown weak bind opcode %d", *p
);
1051 template <typename A
>
1052 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
1054 if ( fInfo
== NULL
) {
1055 printf("no compressed dyld info\n");
1057 else if ( fInfo
->lazy_bind_off() == 0 ) {
1058 printf("no compressed lazy binding info\n");
1061 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1062 printf("segment section address index dylib symbol\n");
1063 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1064 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1066 uint8_t type
= BIND_TYPE_POINTER
;
1067 uint8_t segIndex
= 0;
1068 uint64_t segOffset
= 0;
1069 const char* symbolName
= NULL
;
1070 const char* fromDylib
= "??";
1071 int libraryOrdinal
= 0;
1073 uint32_t lazy_offset
= 0;
1074 pint_t segStartAddr
= 0;
1075 const char* segName
= "??";
1076 const char* typeName
= "??";
1077 const char* weak_import
= "";
1078 for (const uint8_t* p
=start
; p
< end
; ) {
1079 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1080 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1083 case BIND_OPCODE_DONE
:
1084 lazy_offset
= p
-start
;
1086 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1087 libraryOrdinal
= immediate
;
1088 fromDylib
= ordinalName(libraryOrdinal
);
1090 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1091 libraryOrdinal
= read_uleb128(p
, end
);
1092 fromDylib
= ordinalName(libraryOrdinal
);
1094 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1095 // the special ordinals are negative numbers
1096 if ( immediate
== 0 )
1099 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1100 libraryOrdinal
= signExtended
;
1102 fromDylib
= ordinalName(libraryOrdinal
);
1104 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1105 symbolName
= (char*)p
;
1109 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
1110 weak_import
= " (weak import)";
1114 case BIND_OPCODE_SET_TYPE_IMM
:
1116 typeName
= bindTypeName(type
);
1118 case BIND_OPCODE_SET_ADDEND_SLEB
:
1119 addend
= read_sleb128(p
, end
);
1121 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1122 segIndex
= immediate
;
1123 segStartAddr
= segStartAddress(segIndex
);
1124 segName
= segmentName(segIndex
);
1125 segOffset
= read_uleb128(p
, end
);
1127 case BIND_OPCODE_ADD_ADDR_ULEB
:
1128 segOffset
+= read_uleb128(p
, end
);
1130 case BIND_OPCODE_DO_BIND
:
1131 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
, weak_import
);
1132 segOffset
+= sizeof(pint_t
);
1135 throwf("bad lazy bind opcode %d", *p
);
1142 template <typename A
>
1143 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1145 if ( fInfo
== NULL
) {
1146 printf("no compressed dyld info\n");
1148 else if ( fInfo
->lazy_bind_off() == 0 ) {
1149 printf("no compressed lazy binding info\n");
1152 printf("lazy binding opcodes:\n");
1153 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1154 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1155 uint8_t type
= BIND_TYPE_POINTER
;
1157 uint64_t address
= fBaseAddress
;
1158 const char* symbolName
= NULL
;
1159 int libraryOrdinal
= 0;
1161 uint32_t segmentIndex
= 0;
1164 for (const uint8_t* p
= start
; p
< end
; ) {
1165 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1166 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1167 uint32_t opcodeOffset
= p
-start
;
1170 case BIND_OPCODE_DONE
:
1171 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1173 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1174 libraryOrdinal
= immediate
;
1175 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1177 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1178 libraryOrdinal
= read_uleb128(p
, end
);
1179 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1181 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1182 // the special ordinals are negative numbers
1183 if ( immediate
== 0 )
1186 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1187 libraryOrdinal
= signExtended
;
1189 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1191 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1193 symbolName
= (char*)p
;
1197 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1199 case BIND_OPCODE_SET_TYPE_IMM
:
1201 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1203 case BIND_OPCODE_SET_ADDEND_SLEB
:
1204 addend
= read_sleb128(p
, end
);
1205 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1207 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1208 segmentIndex
= immediate
;
1209 address
= read_uleb128(p
, end
);
1210 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1212 case BIND_OPCODE_ADD_ADDR_ULEB
:
1213 skip
= read_uleb128(p
, end
);
1214 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1216 case BIND_OPCODE_DO_BIND
:
1217 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1219 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1220 skip
= read_uleb128(p
, end
);
1221 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1223 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1224 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1225 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1227 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1228 count
= read_uleb128(p
, end
);
1229 skip
= read_uleb128(p
, end
);
1230 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1233 throwf("unknown bind opcode %d", *p
);
1240 struct SortExportsByAddress
1242 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1244 return ( left
.address
< right
.address
);
1248 template <typename A
>
1249 void DyldInfoPrinter
<A
>::printExportInfo()
1251 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1252 printf("no compressed export info\n");
1255 printf("export information (from trie):\n");
1256 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1257 const uint8_t* end
= &start
[fInfo
->export_size()];
1258 std::vector
<mach_o::trie::Entry
> list
;
1259 parseTrie(start
, end
, list
);
1260 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1261 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1262 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1263 if ( it
->importName
[0] == '\0' )
1264 fprintf(stdout
, "[re-export] %s from dylib=%llu\n", it
->name
, it
->other
);
1266 fprintf(stdout
, "[re-export] %s from dylib=%llu named=%s\n", it
->name
, it
->other
, it
->importName
);
1269 const char* flags
= "";
1270 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
)
1271 flags
= "[weak_def] ";
1272 else if ( (it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1273 flags
= "[per-thread] ";
1274 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1275 flags
= "[resolver] ";
1276 fprintf(stdout
, "0x%08llX %s%s (resolver=0x%08llX)\n", fBaseAddress
+it
->address
, flags
, it
->name
, it
->other
);
1279 fprintf(stdout
, "0x%08llX %s%s\n", fBaseAddress
+it
->address
, flags
, it
->name
);
1287 template <typename A
>
1288 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1289 const uint8_t* parent
, const uint8_t* p
,
1290 char* cummulativeString
, int curStrOffset
)
1292 const uint8_t* const me
= p
;
1293 const uint8_t terminalSize
= read_uleb128(p
, end
);
1294 const uint8_t* children
= p
+ terminalSize
;
1295 if ( terminalSize
!= 0 ) {
1296 uint32_t flags
= read_uleb128(p
, end
);
1297 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1298 uint64_t ordinal
= read_uleb128(p
, end
);
1299 const char* importName
= (const char*)p
;
1303 if ( *importName
== '\0' )
1304 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, ordinal
);
1306 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, importName
, ordinal
);
1309 uint64_t address
= read_uleb128(p
, end
);
1310 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1311 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
1312 read_uleb128(p
, end
);
1316 printf("\tnode%03ld;\n", (long)(me
-start
));
1318 const uint8_t childrenCount
= *children
++;
1319 const uint8_t* s
= children
;
1320 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1321 const char* edgeName
= (char*)s
;
1323 while (*s
!= '\0') {
1324 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1327 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1328 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1329 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1330 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1334 template <typename A
>
1335 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1337 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1338 printf("no compressed export info\n");
1341 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1342 const uint8_t* end
= &p
[fInfo
->export_size()];
1343 char cummulativeString
[2000];
1344 printf("digraph {\n");
1345 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1350 template <typename A
>
1351 void DyldInfoPrinter
<A
>::gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
1352 const uint8_t* parent
, const uint8_t* p
,
1353 std::vector
<uint32_t>& nodeStarts
)
1355 nodeStarts
.push_back(p
-start
);
1356 const uint8_t terminalSize
= read_uleb128(p
, end
);
1357 const uint8_t* children
= p
+ terminalSize
;
1359 const uint8_t childrenCount
= *children
++;
1360 const uint8_t* s
= children
;
1361 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1362 // skip over edge string
1366 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1367 gatherNodeStarts(start
, end
, start
, start
+childNodeOffet
, nodeStarts
);
1372 template <typename A
>
1373 void DyldInfoPrinter
<A
>::printExportInfoNodes()
1375 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1376 printf("no compressed export info\n");
1379 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1380 const uint8_t* end
= &start
[fInfo
->export_size()];
1381 std::vector
<uint32_t> nodeStarts
;
1382 gatherNodeStarts(start
, end
, start
, start
, nodeStarts
);
1383 std::sort(nodeStarts
.begin(), nodeStarts
.end());
1384 for (std::vector
<uint32_t>::const_iterator it
=nodeStarts
.begin(); it
!= nodeStarts
.end(); ++it
) {
1385 printf("0x%04X: ", *it
);
1386 const uint8_t* p
= start
+ *it
;
1387 uint64_t exportInfoSize
= read_uleb128(p
, end
);
1388 if ( exportInfoSize
!= 0 ) {
1389 // print terminal info
1390 uint64_t flags
= read_uleb128(p
, end
);
1391 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1392 uint64_t ordinal
= read_uleb128(p
, end
);
1393 const char* importName
= (const char*)p
;
1397 if ( strlen(importName
) == 0 )
1398 printf("[flags=REEXPORT ordinal=%llu] ", ordinal
);
1400 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal
, importName
);
1402 else if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1403 uint64_t stub
= read_uleb128(p
, end
);
1404 uint64_t resolver
= read_uleb128(p
, end
);
1405 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub
, resolver
);
1408 uint64_t address
= read_uleb128(p
, end
);
1409 if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR
)
1410 printf("[addr=0x%06llX] ", address
);
1411 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1412 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address
);
1414 printf("[flags=0x%llX addr=0x%06llX] ", flags
, address
);
1417 // print child edges
1418 const uint8_t childrenCount
= *p
++;
1419 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1420 const char* edgeName
= (const char*)p
;
1424 uint32_t childNodeOffet
= read_uleb128(p
, end
);
1425 printf("%s->0x%04X", edgeName
, childNodeOffet
);
1426 if ( i
< (childrenCount
-1) )
1436 template <typename A
>
1437 const uint8_t* DyldInfoPrinter
<A
>::printSharedRegionInfoForEachULEB128Address(const uint8_t* p
, uint8_t kind
)
1439 const char* kindStr
= "??";
1442 kindStr
= "32-bit pointer";
1445 kindStr
= "64-bit pointer";
1448 kindStr
= "ppc hi16";
1451 kindStr
= "32-bit offset to IMPORT";
1454 kindStr
= "thumb2 movw";
1457 kindStr
= "ARM movw";
1460 kindStr
= "thumb2 movt low high 4 bits=0";
1463 kindStr
= "thumb2 movt low high 4 bits=1";
1466 kindStr
= "thumb2 movt low high 4 bits=2";
1469 kindStr
= "thumb2 movt low high 4 bits=3";
1472 kindStr
= "thumb2 movt low high 4 bits=4";
1475 kindStr
= "thumb2 movt low high 4 bits=5";
1478 kindStr
= "thumb2 movt low high 4 bits=6";
1481 kindStr
= "thumb2 movt low high 4 bits=7";
1484 kindStr
= "thumb2 movt low high 4 bits=8";
1487 kindStr
= "thumb2 movt low high 4 bits=9";
1490 kindStr
= "thumb2 movt low high 4 bits=0xA";
1493 kindStr
= "thumb2 movt low high 4 bits=0xB";
1496 kindStr
= "thumb2 movt low high 4 bits=0xC";
1499 kindStr
= "thumb2 movt low high 4 bits=0xD";
1502 kindStr
= "thumb2 movt low high 4 bits=0xE";
1505 kindStr
= "thumb2 movt low high 4 bits=0xF";
1508 uint64_t address
= 0;
1513 uint8_t byte
= *p
++;
1514 delta
|= ((byte
& 0x7F) << shift
);
1516 if ( byte
< 0x80 ) {
1519 printf("0x%0llX %s\n", address
+fBaseAddress
, kindStr
);
1531 template <typename A
>
1532 void DyldInfoPrinter
<A
>::printSharedRegionInfo()
1534 if ( (fSharedRegionInfo
== NULL
) || (fSharedRegionInfo
->datasize() == 0) ) {
1535 printf("no shared region info\n");
1538 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fSharedRegionInfo
->dataoff();
1539 const uint8_t* infoEnd
= &infoStart
[fSharedRegionInfo
->datasize()];
1540 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
);) {
1541 uint8_t kind
= *p
++;
1542 p
= this->printSharedRegionInfoForEachULEB128Address(p
, kind
);
1549 void DyldInfoPrinter
<arm
>::printFunctionStartLine(uint64_t addr
)
1552 printf("0x%0llX [thumb] %s\n", (addr
& -2), symbolNameForAddress(addr
& -2));
1554 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1557 template <typename A
>
1558 void DyldInfoPrinter
<A
>::printFunctionStartLine(uint64_t addr
)
1560 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1564 template <typename A
>
1565 void DyldInfoPrinter
<A
>::printFunctionStartsInfo()
1567 if ( (fFunctionStartsInfo
== NULL
) || (fFunctionStartsInfo
->datasize() == 0) ) {
1568 printf("no function starts info\n");
1571 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fFunctionStartsInfo
->dataoff();
1572 const uint8_t* infoEnd
= &infoStart
[fFunctionStartsInfo
->datasize()];
1573 uint64_t address
= fBaseAddress
;
1574 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
); ) {
1579 uint8_t byte
= *p
++;
1580 delta
|= ((byte
& 0x7F) << shift
);
1582 if ( byte
< 0x80 ) {
1584 printFunctionStartLine(address
);
1592 template <typename A
>
1593 void DyldInfoPrinter
<A
>::printDylibsInfo()
1595 printf("attributes dependent dylibs\n");
1596 for(typename
std::vector
<const macho_dylib_command
<P
>*>::iterator it
= fDylibLoadCommands
.begin(); it
!= fDylibLoadCommands
.end(); ++it
) {
1597 const macho_dylib_command
<P
>* dylib
= *it
;
1598 const char* attribute
= "";
1599 switch ( dylib
->cmd() ) {
1600 case LC_LOAD_WEAK_DYLIB
:
1601 attribute
= "weak_import";
1603 case LC_REEXPORT_DYLIB
:
1604 attribute
= "re-export";
1606 case LC_LOAD_UPWARD_DYLIB
:
1607 attribute
= "upward";
1609 case LC_LAZY_LOAD_DYLIB
:
1610 attribute
= "lazy_load";
1616 printf(" %-12s %s\n", attribute
, dylib
->name());
1622 ppc::P::uint_t DyldInfoPrinter
<ppc
>::relocBase()
1624 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1625 return fFirstWritableSegment
->vmaddr();
1627 return fFirstSegment
->vmaddr();
1631 ppc64::P::uint_t DyldInfoPrinter
<ppc64
>::relocBase()
1633 if ( fWriteableSegmentWithAddrOver4G
)
1634 return fFirstWritableSegment
->vmaddr();
1636 return fFirstSegment
->vmaddr();
1640 x86::P::uint_t DyldInfoPrinter
<x86
>::relocBase()
1642 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1643 return fFirstWritableSegment
->vmaddr();
1645 return fFirstSegment
->vmaddr();
1649 x86_64::P::uint_t DyldInfoPrinter
<x86_64
>::relocBase()
1651 // check for split-seg
1652 return fFirstWritableSegment
->vmaddr();
1656 arm::P::uint_t DyldInfoPrinter
<arm
>::relocBase()
1658 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1659 return fFirstWritableSegment
->vmaddr();
1661 return fFirstSegment
->vmaddr();
1666 const char* DyldInfoPrinter
<ppc
>::relocTypeName(uint8_t r_type
)
1668 if ( r_type
== GENERIC_RELOC_VANILLA
)
1675 const char* DyldInfoPrinter
<ppc64
>::relocTypeName(uint8_t r_type
)
1677 if ( r_type
== GENERIC_RELOC_VANILLA
)
1684 const char* DyldInfoPrinter
<x86
>::relocTypeName(uint8_t r_type
)
1686 if ( r_type
== GENERIC_RELOC_VANILLA
)
1688 else if ( r_type
== GENERIC_RELOC_PB_LA_PTR
)
1689 return "pb pointer";
1695 const char* DyldInfoPrinter
<x86_64
>::relocTypeName(uint8_t r_type
)
1697 if ( r_type
== X86_64_RELOC_UNSIGNED
)
1704 const char* DyldInfoPrinter
<arm
>::relocTypeName(uint8_t r_type
)
1706 if ( r_type
== ARM_RELOC_VANILLA
)
1708 else if ( r_type
== ARM_RELOC_PB_LA_PTR
)
1709 return "pb pointer";
1715 template <typename A
>
1716 void DyldInfoPrinter
<A
>::printRelocRebaseInfo()
1718 if ( fDynamicSymbolTable
== NULL
) {
1719 printf("no classic dynamic symbol table");
1722 printf("rebase information (from local relocation records and indirect symbol table):\n");
1723 printf("segment section address type\n");
1724 // walk all local relocations
1725 pint_t rbase
= relocBase();
1726 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->locreloff());
1727 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nlocrel()];
1728 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1729 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
1730 pint_t addr
= reloc
->r_address() + rbase
;
1731 uint8_t segIndex
= segmentIndexForAddress(addr
);
1732 const char* typeName
= relocTypeName(reloc
->r_type());
1733 const char* segName
= segmentName(segIndex
);
1734 const char* sectName
= sectionName(segIndex
, addr
);
1735 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1738 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
1739 pint_t addr
= sreloc
->r_address() + rbase
;
1740 uint8_t segIndex
= segmentIndexForAddress(addr
);
1741 const char* typeName
= relocTypeName(sreloc
->r_type());
1742 const char* segName
= segmentName(segIndex
);
1743 const char* sectName
= sectionName(segIndex
, addr
);
1744 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1747 // look for local non-lazy-pointers
1748 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1749 uint8_t segIndex
= 0;
1750 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
, ++segIndex
) {
1751 const macho_segment_command
<P
>* segCmd
= *segit
;
1752 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1753 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1754 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1755 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1756 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
1757 uint32_t indirectOffset
= sect
->reserved1();
1758 uint32_t count
= sect
->size() / sizeof(pint_t
);
1759 for (uint32_t i
=0; i
< count
; ++i
) {
1760 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1761 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
1762 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1763 const char* typeName
= "pointer";
1764 const char* segName
= segmentName(segIndex
);
1765 const char* sectName
= sectionName(segIndex
, addr
);
1766 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1776 template <typename A
>
1777 void DyldInfoPrinter
<A
>::printSymbolTableExportInfo()
1779 if ( fDynamicSymbolTable
== NULL
) {
1780 printf("no classic dynamic symbol table");
1783 printf("export information (from symbol table):\n");
1784 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1785 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1786 const char* flags
= "";
1787 if ( sym
->n_desc() & N_WEAK_DEF
)
1788 flags
= "[weak_def] ";
1790 if ( sym
->n_desc() & N_ARM_THUMB_DEF
)
1792 printf("0x%08llX %s%s\n", sym
->n_value()+thumb
, flags
, &fStrings
[sym
->n_strx()]);
1797 template <typename A
>
1798 const char* DyldInfoPrinter
<A
>::symbolNameForAddress(uint64_t addr
)
1800 if ( fDynamicSymbolTable
!= NULL
) {
1801 // find exact match in globals
1802 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1803 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1804 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1805 return &fStrings
[sym
->n_strx()];
1808 // find exact match in local symbols
1809 const macho_nlist
<P
>* lastLocal
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1810 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()]; sym
< lastLocal
; ++sym
) {
1811 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1812 return &fStrings
[sym
->n_strx()];
1817 // find exact match in all symbols
1818 const macho_nlist
<P
>* lastSym
= &fSymbols
[fSymbolCount
];
1819 for (const macho_nlist
<P
>* sym
= &fSymbols
[0]; sym
< lastSym
; ++sym
) {
1820 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1821 return &fStrings
[sym
->n_strx()];
1829 template <typename A
>
1830 void DyldInfoPrinter
<A
>::printClassicBindingInfo()
1832 if ( fDynamicSymbolTable
== NULL
) {
1833 printf("no classic dynamic symbol table");
1836 printf("binding information (from relocations and indirect symbol table):\n");
1837 printf("segment section address type weak addend dylib symbol\n");
1838 // walk all external relocations
1839 pint_t rbase
= relocBase();
1840 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->extreloff());
1841 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1842 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1843 pint_t addr
= reloc
->r_address() + rbase
;
1844 uint32_t symbolIndex
= reloc
->r_symbolnum();
1845 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1846 const char* symbolName
= &fStrings
[sym
->n_strx()];
1847 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
1848 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1849 uint8_t segIndex
= segmentIndexForAddress(addr
);
1850 const char* typeName
= relocTypeName(reloc
->r_type());
1851 const char* segName
= segmentName(segIndex
);
1852 const char* sectName
= sectionName(segIndex
, addr
);
1853 const pint_t
* addressMapped
= mappedAddressForVMAddress(addr
);
1854 int64_t addend
= P::getP(*addressMapped
);
1855 if ( fHeader
->flags() & MH_PREBOUND
) {
1856 // In prebound binaries the content is already pointing to the target.
1857 // To get the addend requires subtracting out the base address it was prebound to.
1858 addend
-= sym
->n_value();
1860 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1861 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
1863 // look for non-lazy pointers
1864 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1865 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
1866 const macho_segment_command
<P
>* segCmd
= *segit
;
1867 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1868 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1869 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1870 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1871 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
1872 uint32_t indirectOffset
= sect
->reserved1();
1873 uint32_t count
= sect
->size() / sizeof(pint_t
);
1874 for (uint32_t i
=0; i
< count
; ++i
) {
1875 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1876 if ( symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
1877 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1878 const char* symbolName
= &fStrings
[sym
->n_strx()];
1879 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
1880 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1881 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1882 uint8_t segIndex
= segmentIndexForAddress(addr
);
1883 const char* typeName
= "pointer";
1884 const char* segName
= segmentName(segIndex
);
1885 const char* sectName
= sectionName(segIndex
, addr
);
1887 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1888 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
1898 template <typename A
>
1899 void DyldInfoPrinter
<A
>::printClassicLazyBindingInfo()
1901 if ( fDynamicSymbolTable
== NULL
) {
1902 printf("no classic dynamic symbol table");
1905 printf("lazy binding information (from section records and indirect symbol table):\n");
1906 printf("segment section address index dylib symbol\n");
1907 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1908 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
1909 const macho_segment_command
<P
>* segCmd
= *segit
;
1910 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1911 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1912 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1913 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1914 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
1915 uint32_t indirectOffset
= sect
->reserved1();
1916 uint32_t count
= sect
->size() / sizeof(pint_t
);
1917 for (uint32_t i
=0; i
< count
; ++i
) {
1918 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1919 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1920 const char* symbolName
= &fStrings
[sym
->n_strx()];
1921 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1922 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1923 uint8_t segIndex
= segmentIndexForAddress(addr
);
1924 const char* segName
= segmentName(segIndex
);
1925 const char* sectName
= sectionName(segIndex
, addr
);
1926 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
1929 else if ( (type
== S_SYMBOL_STUBS
) && (((sect
->flags() & S_ATTR_SELF_MODIFYING_CODE
) != 0)) && (sect
->reserved2() == 5) ) {
1930 // i386 self-modifying stubs
1931 uint32_t indirectOffset
= sect
->reserved1();
1932 uint32_t count
= sect
->size() / 5;
1933 for (uint32_t i
=0; i
< count
; ++i
) {
1934 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1935 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
1936 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1937 const char* symbolName
= &fStrings
[sym
->n_strx()];
1938 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1939 pint_t addr
= sect
->addr() + i
*5;
1940 uint8_t segIndex
= segmentIndexForAddress(addr
);
1941 const char* segName
= segmentName(segIndex
);
1942 const char* sectName
= sectionName(segIndex
, addr
);
1943 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
1952 static void dump(const char* path
)
1954 struct stat stat_buf
;
1957 int fd
= ::open(path
, O_RDONLY
, 0);
1959 throw "cannot open file";
1960 if ( ::fstat(fd
, &stat_buf
) != 0 )
1961 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
1962 uint32_t length
= stat_buf
.st_size
;
1963 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1964 if ( p
== ((uint8_t*)(-1)) )
1965 throw "cannot map file";
1967 const mach_header
* mh
= (mach_header
*)p
;
1968 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1969 const struct fat_header
* fh
= (struct fat_header
*)p
;
1970 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1971 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1972 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1973 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
1974 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
1975 cpu_type_t cpusubtype
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
);
1976 if ( ((cputype
== sPreferredArch
)
1977 && ((sPreferredSubArch
==0) || (sPreferredSubArch
==cpusubtype
)))
1978 || (sPreferredArch
== 0) ) {
1980 case CPU_TYPE_POWERPC
:
1981 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
1982 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
1984 throw "in universal file, ppc slice does not contain ppc mach-o";
1987 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
1988 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
1990 throw "in universal file, i386 slice does not contain i386 mach-o";
1992 case CPU_TYPE_POWERPC64
:
1993 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
1994 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
1996 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
1998 case CPU_TYPE_X86_64
:
1999 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
2000 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2002 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
2005 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
2006 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2008 throw "in universal file, arm slice does not contain arm mach-o";
2011 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
2016 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
2017 DyldInfoPrinter
<x86
>::make(p
, length
, path
, false);
2019 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
2020 DyldInfoPrinter
<ppc
>::make(p
, length
, path
, false);
2022 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
2023 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
, false);
2025 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
2026 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
, false);
2028 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
2029 DyldInfoPrinter
<arm
>::make(p
, length
, path
, false);
2032 throw "not a known file type";
2035 catch (const char* msg
) {
2036 throwf("%s in %s", msg
, path
);
2042 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
2043 "\t-dylibs print dependent dylibs\n"
2044 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
2045 "\t-bind print addresses dyld will set based on symbolic lookups\n"
2046 "\t-weak_bind print symbols which dyld must coalesce\n"
2047 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
2048 "\t-export print addresses of all symbols this file exports\n"
2049 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
2050 "\t-function_starts print table of function start addresses\n"
2051 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
2056 int main(int argc
, const char* argv
[])
2064 std::vector
<const char*> files
;
2065 for(int i
=1; i
< argc
; ++i
) {
2066 const char* arg
= argv
[i
];
2067 if ( arg
[0] == '-' ) {
2068 if ( strcmp(arg
, "-arch") == 0 ) {
2069 const char* arch
= ++i
<argc
? argv
[i
]: "";
2070 if ( strcmp(arch
, "ppc64") == 0 )
2071 sPreferredArch
= CPU_TYPE_POWERPC64
;
2072 else if ( strcmp(arch
, "ppc") == 0 )
2073 sPreferredArch
= CPU_TYPE_POWERPC
;
2074 else if ( strcmp(arch
, "i386") == 0 )
2075 sPreferredArch
= CPU_TYPE_I386
;
2076 else if ( strcmp(arch
, "x86_64") == 0 )
2077 sPreferredArch
= CPU_TYPE_X86_64
;
2080 for (const ARMSubType
* t
=ARMSubTypes
; t
->subTypeName
!= NULL
; ++t
) {
2081 if ( strcmp(t
->subTypeName
,arch
) == 0 ) {
2082 sPreferredArch
= CPU_TYPE_ARM
;
2083 sPreferredSubArch
= t
->subType
;
2089 throwf("unknown architecture %s", arch
);
2092 else if ( strcmp(arg
, "-rebase") == 0 ) {
2095 else if ( strcmp(arg
, "-bind") == 0 ) {
2098 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
2099 printWeakBind
= true;
2101 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
2102 printLazyBind
= true;
2104 else if ( strcmp(arg
, "-export") == 0 ) {
2107 else if ( strcmp(arg
, "-opcodes") == 0 ) {
2108 printOpcodes
= true;
2110 else if ( strcmp(arg
, "-export_dot") == 0 ) {
2111 printExportGraph
= true;
2113 else if ( strcmp(arg
, "-export_trie_nodes") == 0 ) {
2114 printExportNodes
= true;
2116 else if ( strcmp(arg
, "-shared_region") == 0 ) {
2117 printSharedRegion
= true;
2119 else if ( strcmp(arg
, "-function_starts") == 0 ) {
2120 printFunctionStarts
= true;
2122 else if ( strcmp(arg
, "-dylibs") == 0 ) {
2126 throwf("unknown option: %s\n", arg
);
2130 files
.push_back(arg
);
2133 if ( files
.size() == 0 )
2135 if ( files
.size() == 1 ) {
2139 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
2140 printf("\n%s:\n", *it
);
2145 catch (const char* msg
) {
2146 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);