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 <unordered_set>
38 #include "configure.h"
39 #include "MachOFileAbstraction.hpp"
40 #include "Architectures.hpp"
41 #include "MachOTrie.hpp"
42 #include "../ld/code-sign-blobs/superblob.h"
44 static bool printRebase
= false;
45 static bool printBind
= false;
46 static bool printWeakBind
= false;
47 static bool printLazyBind
= false;
48 static bool printOpcodes
= false;
49 static bool printExport
= false;
50 static bool printExportGraph
= false;
51 static bool printExportNodes
= false;
52 static bool printSharedRegion
= false;
53 static bool printFunctionStarts
= false;
54 static bool printDylibs
= false;
55 static bool printDRs
= false;
56 static bool printDataCode
= false;
57 static cpu_type_t sPreferredArch
= 0;
58 static cpu_type_t sPreferredSubArch
= 0;
61 __attribute__((noreturn
))
62 static void throwf(const char* format
, ...)
66 va_start(list
, format
);
67 vasprintf(&p
, format
, list
);
79 static bool validFile(const uint8_t* fileContent
);
80 static DyldInfoPrinter
<A
>* make(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
81 { return new DyldInfoPrinter
<A
>(fileContent
, fileLength
, path
, printArch
); }
82 virtual ~DyldInfoPrinter() {}
86 typedef typename
A::P P
;
87 typedef typename
A::P::E E
;
88 typedef typename
A::P::uint_t pint_t
;
90 DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
);
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 printExportInfoNodes();
102 void printRelocRebaseInfo();
103 void printSymbolTableExportInfo();
104 void printClassicLazyBindingInfo();
105 void printClassicBindingInfo();
106 void printSharedRegionInfo();
107 const char* sharedRegionKindName(uint8_t kind
);
108 void printFunctionStartsInfo();
109 void printDylibsInfo();
111 void printDataInCode();
112 void printFunctionStartLine(uint64_t addr
);
113 const uint8_t* printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p
, const uint8_t* end
, uint8_t kind
);
114 const uint8_t* printSharedRegionV2InfoForEachULEB128Address(const uint8_t* p
, const uint8_t* end
);
115 const uint8_t* printSharedRegionV2InfoForEachULEB128AddressAndAdj(const uint8_t* p
, const uint8_t* end
);
116 const uint8_t* printSharedRegionV2SectionPair(const uint8_t* p
, const uint8_t* end
);
117 const uint8_t* printSharedRegionV2ToSectionOffset(const uint8_t* p
, const uint8_t* end
);
118 const uint8_t* printSharedRegionV2Kind(const uint8_t* p
, const uint8_t* end
);
121 const char* relocTypeName(uint8_t r_type
);
122 uint8_t segmentIndexForAddress(pint_t addr
);
123 void processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
124 const uint8_t* parent
, const uint8_t* p
,
125 char* cummulativeString
, int curStrOffset
);
126 void gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
127 const uint8_t* parent
, const uint8_t* p
,
128 std::vector
<uint32_t>& nodeStarts
);
129 const char* rebaseTypeName(uint8_t type
);
130 const char* bindTypeName(uint8_t type
);
131 pint_t
segStartAddress(uint8_t segIndex
);
132 const char* segmentName(uint8_t segIndex
);
133 const char* sectionName(uint8_t segIndex
, pint_t address
);
134 const char* getSegAndSectName(uint8_t segIndex
, pint_t address
);
135 const char* ordinalName(int libraryOrdinal
);
136 const char* classicOrdinalName(int libraryOrdinal
);
137 pint_t
* mappedAddressForVMAddress(pint_t vmaddress
);
138 const char* symbolNameForAddress(uint64_t);
139 const char* closestSymbolNameForAddress(uint64_t addr
, uint64_t* offset
, uint8_t sectIndex
=0);
143 const macho_header
<P
>* fHeader
;
145 const char* fStrings
;
146 const char* fStringsEnd
;
147 const macho_nlist
<P
>* fSymbols
;
148 uint32_t fSymbolCount
;
149 const macho_dyld_info_command
<P
>* fInfo
;
150 const macho_linkedit_data_command
<P
>* fSharedRegionInfo
;
151 const macho_linkedit_data_command
<P
>* fFunctionStartsInfo
;
152 const macho_linkedit_data_command
<P
>* fDataInCode
;
153 const macho_linkedit_data_command
<P
>* fDRInfo
;
154 uint64_t fBaseAddress
;
155 const macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
156 const macho_segment_command
<P
>* fFirstSegment
;
157 const macho_segment_command
<P
>* fFirstWritableSegment
;
158 bool fWriteableSegmentWithAddrOver4G
;
159 std::vector
<const macho_segment_command
<P
>*>fSegments
;
160 std::vector
<const macho_section
<P
>*> fSections
;
161 std::vector
<const char*> fDylibs
;
162 std::vector
<const macho_dylib_command
<P
>*> fDylibLoadCommands
;
163 macho_section
<P
> fMachHeaderPseudoSection
;
169 bool DyldInfoPrinter
<ppc
>::validFile(const uint8_t* fileContent
)
171 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
172 if ( header
->magic() != MH_MAGIC
)
174 if ( header
->cputype() != CPU_TYPE_POWERPC
)
176 switch (header
->filetype()) {
188 bool DyldInfoPrinter
<ppc64
>::validFile(const uint8_t* fileContent
)
190 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
191 if ( header
->magic() != MH_MAGIC_64
)
193 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
195 switch (header
->filetype()) {
207 bool DyldInfoPrinter
<x86
>::validFile(const uint8_t* fileContent
)
209 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
210 if ( header
->magic() != MH_MAGIC
)
212 if ( header
->cputype() != CPU_TYPE_I386
)
214 switch (header
->filetype()) {
226 bool DyldInfoPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
228 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
229 if ( header
->magic() != MH_MAGIC_64
)
231 if ( header
->cputype() != CPU_TYPE_X86_64
)
233 switch (header
->filetype()) {
244 #if SUPPORT_ARCH_arm_any
246 bool DyldInfoPrinter
<arm
>::validFile(const uint8_t* fileContent
)
248 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
249 if ( header
->magic() != MH_MAGIC
)
251 if ( header
->cputype() != CPU_TYPE_ARM
)
253 switch (header
->filetype()) {
265 #if SUPPORT_ARCH_arm64
267 bool DyldInfoPrinter
<arm64
>::validFile(const uint8_t* fileContent
)
269 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
270 if ( header
->magic() != MH_MAGIC_64
)
272 if ( header
->cputype() != CPU_TYPE_ARM64
)
274 switch (header
->filetype()) {
285 template <typename A
>
286 DyldInfoPrinter
<A
>::DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
287 : fHeader(NULL
), fLength(fileLength
),
288 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fInfo(NULL
),
289 fSharedRegionInfo(NULL
), fFunctionStartsInfo(NULL
), fDataInCode(NULL
), fDRInfo(NULL
),
290 fBaseAddress(0), fDynamicSymbolTable(NULL
), fFirstSegment(NULL
), fFirstWritableSegment(NULL
),
291 fWriteableSegmentWithAddrOver4G(false)
294 if ( ! validFile(fileContent
) )
295 throw "not a mach-o file that can be checked";
297 fPath
= strdup(path
);
298 fHeader
= (const macho_header
<P
>*)fileContent
;
300 fMachHeaderPseudoSection
.set_segname("__TEXT");
301 fMachHeaderPseudoSection
.set_sectname("");
302 fMachHeaderPseudoSection
.set_addr(0);
303 fSections
.push_back(&fMachHeaderPseudoSection
);
306 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
307 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
308 const uint32_t cmd_count
= fHeader
->ncmds();
309 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
310 const macho_load_command
<P
>* cmd
= cmds
;
311 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
312 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
313 if ( endOfCmd
> endOfLoadCommands
)
314 throwf("load command #%d extends beyond the end of the load commands", i
);
315 if ( endOfCmd
> endOfFile
)
316 throwf("load command #%d extends beyond the end of the file", i
);
317 switch ( cmd
->cmd() ) {
319 case LC_DYLD_INFO_ONLY
:
320 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
322 case macho_segment_command
<P
>::CMD
:
324 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
325 fSegments
.push_back(segCmd
);
326 if ( (segCmd
->fileoff() == 0) && (segCmd
->filesize() != 0) )
327 fBaseAddress
= segCmd
->vmaddr();
328 if ( fFirstSegment
== NULL
)
329 fFirstSegment
= segCmd
;
330 if ( (segCmd
->initprot() & VM_PROT_WRITE
) != 0 ) {
331 if ( fFirstWritableSegment
== NULL
)
332 fFirstWritableSegment
= segCmd
;
333 if ( segCmd
->vmaddr() > 0x100000000ULL
)
334 fWriteableSegmentWithAddrOver4G
= true;
336 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
337 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
338 for(const macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
)
339 fSections
.push_back(sect
);
343 case LC_LOAD_WEAK_DYLIB
:
344 case LC_REEXPORT_DYLIB
:
345 case LC_LOAD_UPWARD_DYLIB
:
346 case LC_LAZY_LOAD_DYLIB
:
348 const macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
349 fDylibLoadCommands
.push_back(dylib
);
350 const char* lastSlash
= strrchr(dylib
->name(), '/');
351 const char* leafName
= (lastSlash
!= NULL
) ? lastSlash
+1 : dylib
->name();
352 const char* firstDot
= strchr(leafName
, '.');
353 if ( firstDot
!= NULL
) {
354 char* t
= strdup(leafName
);
355 t
[firstDot
-leafName
] = '\0';
356 fDylibs
.push_back(t
);
359 fDylibs
.push_back(leafName
);
364 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
368 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
369 fSymbolCount
= symtab
->nsyms();
370 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
371 fStrings
= (char*)fHeader
+ symtab
->stroff();
372 fStringsEnd
= fStrings
+ symtab
->strsize();
375 case LC_SEGMENT_SPLIT_INFO
:
376 fSharedRegionInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
378 case LC_FUNCTION_STARTS
:
379 fFunctionStartsInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
381 case LC_DATA_IN_CODE
:
382 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
384 case LC_DYLIB_CODE_SIGN_DRS
:
385 fDRInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
388 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
392 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
393 if ( (cpu_type_t
)fHeader
->cputype() == t
->cpuType
) {
394 if ( t
->isSubType
&& ((cpu_subtype_t
)fHeader
->cpusubtype() != t
->cpuSubType
) )
396 printf("for arch %s:\n", t
->archName
);
405 printRelocRebaseInfo();
411 printClassicBindingInfo();
414 printWeakBindingInfo();
415 if ( printLazyBind
) {
417 printLazyBindingInfo();
419 printClassicLazyBindingInfo();
425 printSymbolTableExportInfo();
427 if ( printOpcodes
) {
428 printRebaseInfoOpcodes();
429 printBindingInfoOpcodes(false);
430 printBindingInfoOpcodes(true);
431 printLazyBindingOpcodes();
433 if ( printExportGraph
)
434 printExportInfoGraph();
435 if ( printExportNodes
)
436 printExportInfoNodes();
437 if ( printSharedRegion
)
438 printSharedRegionInfo();
439 if ( printFunctionStarts
)
440 printFunctionStartsInfo();
449 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
455 throwf("malformed uleb128");
457 uint64_t slice
= *p
& 0x7f;
459 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
460 throwf("uleb128 too big");
462 result
|= (slice
<< bit
);
470 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
477 throwf("malformed sleb128");
479 result
|= (((int64_t)(byte
& 0x7f)) << bit
);
481 } while (byte
& 0x80);
482 // sign extend negative numbers
483 if ( (byte
& 0x40) != 0 )
484 result
|= (-1LL) << bit
;
489 template <typename A
>
490 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
493 case REBASE_TYPE_POINTER
:
495 case REBASE_TYPE_TEXT_ABSOLUTE32
:
497 case REBASE_TYPE_TEXT_PCREL32
:
500 return "!!unknown!!";
504 template <typename A
>
505 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
508 case BIND_TYPE_POINTER
:
510 case BIND_TYPE_TEXT_ABSOLUTE32
:
512 case BIND_TYPE_TEXT_PCREL32
:
515 return "!!unknown!!";
519 template <typename A
>
520 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
522 if ( segIndex
> fSegments
.size() )
523 throw "segment index out of range";
524 return fSegments
[segIndex
]->vmaddr();
527 template <typename A
>
528 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
530 if ( segIndex
> fSegments
.size() )
531 throw "segment index out of range";
532 return fSegments
[segIndex
]->segname();
535 template <typename A
>
536 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
538 if ( segIndex
> fSegments
.size() )
539 throw "segment index out of range";
540 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
541 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
542 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
543 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
544 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
545 if ( strlen(sect
->sectname()) > 15 ) {
546 static char temp
[18];
547 strlcpy(temp
, sect
->sectname(), 17);
551 return sect
->sectname();
558 template <typename A
>
559 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
561 static char buffer
[64];
562 strcpy(buffer
, segmentName(segIndex
));
564 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
565 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
566 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
567 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
568 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
569 // section name may not be zero terminated
570 char* end
= &buffer
[strlen(buffer
)];
571 strlcpy(end
, sect
->sectname(), 16);
578 template <typename A
>
579 uint8_t DyldInfoPrinter
<A
>::segmentIndexForAddress(pint_t address
)
581 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
582 if ( (fSegments
[i
]->vmaddr() <= address
) && (address
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
586 throwf("address 0x%llX is not in any segment", (uint64_t)address
);
589 template <typename A
>
590 typename
A::P::uint_t
* DyldInfoPrinter
<A
>::mappedAddressForVMAddress(pint_t vmaddress
)
592 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
593 if ( (fSegments
[i
]->vmaddr() <= vmaddress
) && (vmaddress
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
594 unsigned long offsetInMappedFile
= fSegments
[i
]->fileoff()+vmaddress
-fSegments
[i
]->vmaddr();
595 return (pint_t
*)((uint8_t*)fHeader
+ offsetInMappedFile
);
598 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress
);
601 template <typename A
>
602 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
604 switch ( libraryOrdinal
) {
605 case BIND_SPECIAL_DYLIB_SELF
:
607 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
608 return "main-executable";
609 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
610 return "flat-namespace";
612 if ( libraryOrdinal
< BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
613 throw "unknown special ordinal";
614 if ( libraryOrdinal
> (int)fDylibs
.size() )
615 throw "libraryOrdinal out of range";
616 return fDylibs
[libraryOrdinal
-1];
619 template <typename A
>
620 const char* DyldInfoPrinter
<A
>::classicOrdinalName(int libraryOrdinal
)
622 if ( (fHeader
->flags() & MH_TWOLEVEL
) == 0 )
623 return "flat-namespace";
624 switch ( libraryOrdinal
) {
625 case SELF_LIBRARY_ORDINAL
:
627 case EXECUTABLE_ORDINAL
:
628 return "main-executable";
629 case DYNAMIC_LOOKUP_ORDINAL
:
630 return "flat-namespace";
632 if ( libraryOrdinal
> (int)fDylibs
.size() )
633 throw "libraryOrdinal out of range";
634 return fDylibs
[libraryOrdinal
-1];
637 template <typename A
>
638 void DyldInfoPrinter
<A
>::printRebaseInfo()
640 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
641 printf("no compressed rebase info\n");
644 printf("rebase information (from compressed dyld info):\n");
645 printf("segment section address type\n");
647 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
648 const uint8_t* end
= &p
[fInfo
->rebase_size()];
651 uint64_t segOffset
= 0;
655 pint_t segStartAddr
= 0;
656 const char* segName
= "??";
657 const char* typeName
= "??";
659 while ( !done
&& (p
< end
) ) {
660 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
661 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
664 case REBASE_OPCODE_DONE
:
667 case REBASE_OPCODE_SET_TYPE_IMM
:
669 typeName
= rebaseTypeName(type
);
671 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
672 segIndex
= immediate
;
673 segStartAddr
= segStartAddress(segIndex
);
674 segName
= segmentName(segIndex
);
675 segOffset
= read_uleb128(p
, end
);
677 case REBASE_OPCODE_ADD_ADDR_ULEB
:
678 segOffset
+= read_uleb128(p
, end
);
680 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
681 segOffset
+= immediate
*sizeof(pint_t
);
683 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
684 for (int i
=0; i
< immediate
; ++i
) {
685 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
686 segOffset
+= sizeof(pint_t
);
689 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
690 count
= read_uleb128(p
, end
);
691 for (uint32_t i
=0; i
< count
; ++i
) {
692 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
693 segOffset
+= sizeof(pint_t
);
696 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
697 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
698 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
700 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
701 count
= read_uleb128(p
, end
);
702 skip
= read_uleb128(p
, end
);
703 for (uint32_t i
=0; i
< count
; ++i
) {
704 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
705 segOffset
+= skip
+ sizeof(pint_t
);
709 throwf("bad rebase opcode %d", *p
);
718 template <typename A
>
719 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
721 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
722 printf("no compressed rebase info\n");
725 printf("rebase opcodes:\n");
726 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
727 const uint8_t* end
= &start
[fInfo
->rebase_size()];
728 const uint8_t* p
= start
;
731 uint64_t address
= fBaseAddress
;
734 unsigned int segmentIndex
;
736 while ( !done
&& (p
< end
) ) {
737 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
738 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
739 uint32_t opcodeOffset
= p
-start
;
742 case REBASE_OPCODE_DONE
:
744 printf("0x%04X REBASE_OPCODE_DONE()\n", opcodeOffset
);
746 case REBASE_OPCODE_SET_TYPE_IMM
:
748 printf("0x%04X REBASE_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
750 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
751 segmentIndex
= immediate
;
752 address
= read_uleb128(p
, end
);
753 printf("0x%04X REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
755 case REBASE_OPCODE_ADD_ADDR_ULEB
:
756 address
= read_uleb128(p
, end
);
757 printf("0x%04X REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", opcodeOffset
, address
);
759 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
760 address
= immediate
*sizeof(pint_t
);
761 printf("0x%04X REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", opcodeOffset
, address
);
763 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
764 printf("0x%04X REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", opcodeOffset
, immediate
);
766 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
767 count
= read_uleb128(p
, end
);
768 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", opcodeOffset
, count
);
770 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
771 skip
= read_uleb128(p
, end
) + sizeof(pint_t
);
772 printf("0x%04X REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", opcodeOffset
, skip
);
774 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
775 count
= read_uleb128(p
, end
);
776 skip
= read_uleb128(p
, end
);
777 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", opcodeOffset
, count
, skip
);
780 throwf("bad rebase opcode %d", *p
);
792 template <typename A
>
793 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
795 if ( fInfo
== NULL
) {
796 printf("no compressed binding info\n");
798 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
799 printf("no compressed binding info\n");
801 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
802 printf("no compressed weak binding info\n");
805 const uint8_t* start
;
808 printf("weak binding opcodes:\n");
809 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
810 end
= &start
[fInfo
->weak_bind_size()];
813 printf("binding opcodes:\n");
814 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
815 end
= &start
[fInfo
->bind_size()];
817 const uint8_t* p
= start
;
820 uint64_t address
= fBaseAddress
;
821 const char* symbolName
= NULL
;
822 int libraryOrdinal
= 0;
824 uint32_t segmentIndex
= 0;
828 while ( !done
&& (p
< end
) ) {
829 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
830 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
831 uint32_t opcodeOffset
= p
-start
;
834 case BIND_OPCODE_DONE
:
836 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
838 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
839 libraryOrdinal
= immediate
;
840 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
842 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
843 libraryOrdinal
= read_uleb128(p
, end
);
844 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
846 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
847 // the special ordinals are negative numbers
848 if ( immediate
== 0 )
851 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
852 libraryOrdinal
= signExtended
;
854 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
856 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
858 symbolName
= (char*)p
;
862 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
864 case BIND_OPCODE_SET_TYPE_IMM
:
866 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
868 case BIND_OPCODE_SET_ADDEND_SLEB
:
869 addend
= read_sleb128(p
, end
);
870 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
872 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
873 segmentIndex
= immediate
;
874 address
= read_uleb128(p
, end
);
875 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
877 case BIND_OPCODE_ADD_ADDR_ULEB
:
878 skip
= read_uleb128(p
, end
);
879 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
881 case BIND_OPCODE_DO_BIND
:
882 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
884 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
885 skip
= read_uleb128(p
, end
);
886 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
888 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
889 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
890 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
892 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
893 count
= read_uleb128(p
, end
);
894 skip
= read_uleb128(p
, end
);
895 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
898 throwf("unknown bind opcode %d", *p
);
907 template <typename A
>
908 void DyldInfoPrinter
<A
>::printBindingInfo()
910 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
911 printf("no compressed binding info\n");
914 printf("bind information:\n");
915 printf("segment section address type addend dylib symbol\n");
916 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->bind_off();
917 const uint8_t* end
= &p
[fInfo
->bind_size()];
920 uint8_t segIndex
= 0;
921 uint64_t segOffset
= 0;
922 const char* symbolName
= NULL
;
923 const char* fromDylib
= "??";
924 int libraryOrdinal
= 0;
928 pint_t segStartAddr
= 0;
929 const char* segName
= "??";
930 const char* typeName
= "??";
931 const char* weak_import
= "";
933 while ( !done
&& (p
< end
) ) {
934 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
935 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
938 case BIND_OPCODE_DONE
:
941 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
942 libraryOrdinal
= immediate
;
943 fromDylib
= ordinalName(libraryOrdinal
);
945 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
946 libraryOrdinal
= read_uleb128(p
, end
);
947 fromDylib
= ordinalName(libraryOrdinal
);
949 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
950 // the special ordinals are negative numbers
951 if ( immediate
== 0 )
954 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
955 libraryOrdinal
= signExtended
;
957 fromDylib
= ordinalName(libraryOrdinal
);
959 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
960 symbolName
= (char*)p
;
964 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
965 weak_import
= " (weak import)";
969 case BIND_OPCODE_SET_TYPE_IMM
:
971 typeName
= bindTypeName(type
);
973 case BIND_OPCODE_SET_ADDEND_SLEB
:
974 addend
= read_sleb128(p
, end
);
976 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
977 segIndex
= immediate
;
978 segStartAddr
= segStartAddress(segIndex
);
979 segName
= segmentName(segIndex
);
980 segOffset
= read_uleb128(p
, end
);
982 case BIND_OPCODE_ADD_ADDR_ULEB
:
983 segOffset
+= read_uleb128(p
, end
);
985 case BIND_OPCODE_DO_BIND
:
986 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
987 segOffset
+= sizeof(pint_t
);
989 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
990 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
991 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
993 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
994 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
995 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
997 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
998 count
= read_uleb128(p
, end
);
999 skip
= read_uleb128(p
, end
);
1000 for (uint32_t i
=0; i
< count
; ++i
) {
1001 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
1002 segOffset
+= skip
+ sizeof(pint_t
);
1006 throwf("bad bind opcode %d", *p
);
1013 template <typename A
>
1014 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
1016 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
1017 printf("no weak binding\n");
1020 printf("weak binding information:\n");
1021 printf("segment section address type addend symbol\n");
1022 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
1023 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
1026 uint8_t segIndex
= 0;
1027 uint64_t segOffset
= 0;
1028 const char* symbolName
= NULL
;
1032 pint_t segStartAddr
= 0;
1033 const char* segName
= "??";
1034 const char* typeName
= "??";
1036 while ( !done
&& (p
< end
) ) {
1037 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1038 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1041 case BIND_OPCODE_DONE
:
1044 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1045 symbolName
= (char*)p
;
1049 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
1050 printf(" strong %s\n", symbolName
);
1052 case BIND_OPCODE_SET_TYPE_IMM
:
1054 typeName
= bindTypeName(type
);
1056 case BIND_OPCODE_SET_ADDEND_SLEB
:
1057 addend
= read_sleb128(p
, end
);
1059 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1060 segIndex
= immediate
;
1061 segStartAddr
= segStartAddress(segIndex
);
1062 segName
= segmentName(segIndex
);
1063 segOffset
= read_uleb128(p
, end
);
1065 case BIND_OPCODE_ADD_ADDR_ULEB
:
1066 segOffset
+= read_uleb128(p
, end
);
1068 case BIND_OPCODE_DO_BIND
:
1069 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1070 segOffset
+= sizeof(pint_t
);
1072 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1073 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1074 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1076 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1077 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1078 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1080 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1081 count
= read_uleb128(p
, end
);
1082 skip
= read_uleb128(p
, end
);
1083 for (uint32_t i
=0; i
< count
; ++i
) {
1084 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1085 segOffset
+= skip
+ sizeof(pint_t
);
1089 throwf("unknown weak bind opcode %d", *p
);
1097 template <typename A
>
1098 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
1100 if ( fInfo
== NULL
) {
1101 printf("no compressed dyld info\n");
1103 else if ( fInfo
->lazy_bind_off() == 0 ) {
1104 printf("no compressed lazy binding info\n");
1107 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1108 printf("segment section address index dylib symbol\n");
1109 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1110 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1112 uint8_t type
= BIND_TYPE_POINTER
;
1113 uint8_t segIndex
= 0;
1114 uint64_t segOffset
= 0;
1115 const char* symbolName
= NULL
;
1116 const char* fromDylib
= "??";
1117 int libraryOrdinal
= 0;
1119 uint32_t lazy_offset
= 0;
1120 pint_t segStartAddr
= 0;
1121 const char* segName
= "??";
1122 const char* typeName
= "??";
1123 const char* weak_import
= "";
1124 for (const uint8_t* p
=start
; p
< end
; ) {
1125 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1126 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1129 case BIND_OPCODE_DONE
:
1130 lazy_offset
= p
-start
;
1132 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1133 libraryOrdinal
= immediate
;
1134 fromDylib
= ordinalName(libraryOrdinal
);
1136 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1137 libraryOrdinal
= read_uleb128(p
, end
);
1138 fromDylib
= ordinalName(libraryOrdinal
);
1140 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1141 // the special ordinals are negative numbers
1142 if ( immediate
== 0 )
1145 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1146 libraryOrdinal
= signExtended
;
1148 fromDylib
= ordinalName(libraryOrdinal
);
1150 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1151 symbolName
= (char*)p
;
1155 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
1156 weak_import
= " (weak import)";
1160 case BIND_OPCODE_SET_TYPE_IMM
:
1162 typeName
= bindTypeName(type
);
1164 case BIND_OPCODE_SET_ADDEND_SLEB
:
1165 addend
= read_sleb128(p
, end
);
1167 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1168 segIndex
= immediate
;
1169 segStartAddr
= segStartAddress(segIndex
);
1170 segName
= segmentName(segIndex
);
1171 segOffset
= read_uleb128(p
, end
);
1173 case BIND_OPCODE_ADD_ADDR_ULEB
:
1174 segOffset
+= read_uleb128(p
, end
);
1176 case BIND_OPCODE_DO_BIND
:
1177 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
, weak_import
);
1178 segOffset
+= sizeof(pint_t
);
1181 throwf("bad lazy bind opcode %d", *p
);
1188 template <typename A
>
1189 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1191 if ( fInfo
== NULL
) {
1192 printf("no compressed dyld info\n");
1194 else if ( fInfo
->lazy_bind_off() == 0 ) {
1195 printf("no compressed lazy binding info\n");
1198 printf("lazy binding opcodes:\n");
1199 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1200 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1201 uint8_t type
= BIND_TYPE_POINTER
;
1203 uint64_t address
= fBaseAddress
;
1204 const char* symbolName
= NULL
;
1205 int libraryOrdinal
= 0;
1207 uint32_t segmentIndex
= 0;
1210 for (const uint8_t* p
= start
; p
< end
; ) {
1211 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1212 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1213 uint32_t opcodeOffset
= p
-start
;
1216 case BIND_OPCODE_DONE
:
1217 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1219 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1220 libraryOrdinal
= immediate
;
1221 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1223 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1224 libraryOrdinal
= read_uleb128(p
, end
);
1225 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1227 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1228 // the special ordinals are negative numbers
1229 if ( immediate
== 0 )
1232 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1233 libraryOrdinal
= signExtended
;
1235 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1237 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1239 symbolName
= (char*)p
;
1243 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1245 case BIND_OPCODE_SET_TYPE_IMM
:
1247 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1249 case BIND_OPCODE_SET_ADDEND_SLEB
:
1250 addend
= read_sleb128(p
, end
);
1251 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1253 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1254 segmentIndex
= immediate
;
1255 address
= read_uleb128(p
, end
);
1256 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1258 case BIND_OPCODE_ADD_ADDR_ULEB
:
1259 skip
= read_uleb128(p
, end
);
1260 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1262 case BIND_OPCODE_DO_BIND
:
1263 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1265 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1266 skip
= read_uleb128(p
, end
);
1267 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1269 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1270 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1271 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1273 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1274 count
= read_uleb128(p
, end
);
1275 skip
= read_uleb128(p
, end
);
1276 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1279 throwf("unknown bind opcode %d", *p
);
1286 struct SortExportsByAddress
1288 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1290 return ( left
.address
< right
.address
);
1294 template <typename A
>
1295 void DyldInfoPrinter
<A
>::printExportInfo()
1297 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1298 printf("no compressed export info\n");
1301 printf("export information (from trie):\n");
1302 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1303 const uint8_t* end
= &start
[fInfo
->export_size()];
1304 std::vector
<mach_o::trie::Entry
> list
;
1305 parseTrie(start
, end
, list
);
1306 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1307 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1308 const bool reExport
= (it
->flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
);
1309 const bool weakDef
= (it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
);
1310 const bool threadLocal
= ((it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
);
1311 const bool abs
= ((it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
);
1312 const bool resolver
= (it
->flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
);
1314 printf("[re-export] ");
1316 printf("0x%08llX ", fBaseAddress
+it
->address
);
1317 printf("%s", it
->name
);
1318 if ( weakDef
|| threadLocal
|| resolver
|| abs
) {
1319 bool needComma
= false;
1325 if ( threadLocal
) {
1328 printf("per-thread");
1340 printf("resolver=0x%08llX", it
->other
);
1346 if ( it
->importName
[0] == '\0' )
1347 printf(" (from %s)", fDylibs
[it
->other
- 1]);
1349 printf(" (%s from %s)", it
->importName
, fDylibs
[it
->other
- 1]);
1357 template <typename A
>
1358 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1359 const uint8_t* parent
, const uint8_t* p
,
1360 char* cummulativeString
, int curStrOffset
)
1362 const uint8_t* const me
= p
;
1363 const uint64_t terminalSize
= read_uleb128(p
, end
);
1364 const uint8_t* children
= p
+ terminalSize
;
1365 if ( terminalSize
!= 0 ) {
1366 uint32_t flags
= read_uleb128(p
, end
);
1367 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1368 uint64_t ordinal
= read_uleb128(p
, end
);
1369 const char* importName
= (const char*)p
;
1373 if ( *importName
== '\0' )
1374 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, ordinal
);
1376 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, importName
, ordinal
);
1379 uint64_t address
= read_uleb128(p
, end
);
1380 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1381 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
1382 read_uleb128(p
, end
);
1386 printf("\tnode%03ld;\n", (long)(me
-start
));
1388 const uint8_t childrenCount
= *children
++;
1389 const uint8_t* s
= children
;
1390 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1391 const char* edgeName
= (char*)s
;
1393 while (*s
!= '\0') {
1394 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1397 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1398 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1399 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1400 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1404 template <typename A
>
1405 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1407 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1408 printf("no compressed export info\n");
1411 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1412 const uint8_t* end
= &p
[fInfo
->export_size()];
1413 char cummulativeString
[2000];
1414 printf("digraph {\n");
1415 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1420 template <typename A
>
1421 void DyldInfoPrinter
<A
>::gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
1422 const uint8_t* parent
, const uint8_t* p
,
1423 std::vector
<uint32_t>& nodeStarts
)
1425 nodeStarts
.push_back(p
-start
);
1426 const uint8_t terminalSize
= read_uleb128(p
, end
);
1427 const uint8_t* children
= p
+ terminalSize
;
1429 const uint8_t childrenCount
= *children
++;
1430 const uint8_t* s
= children
;
1431 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1432 // skip over edge string
1436 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1437 gatherNodeStarts(start
, end
, start
, start
+childNodeOffet
, nodeStarts
);
1442 template <typename A
>
1443 void DyldInfoPrinter
<A
>::printExportInfoNodes()
1445 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1446 printf("no compressed export info\n");
1449 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1450 const uint8_t* end
= &start
[fInfo
->export_size()];
1451 std::vector
<uint32_t> nodeStarts
;
1452 gatherNodeStarts(start
, end
, start
, start
, nodeStarts
);
1453 std::sort(nodeStarts
.begin(), nodeStarts
.end());
1454 for (std::vector
<uint32_t>::const_iterator it
=nodeStarts
.begin(); it
!= nodeStarts
.end(); ++it
) {
1455 printf("0x%04X: ", *it
);
1456 const uint8_t* p
= start
+ *it
;
1457 uint64_t exportInfoSize
= read_uleb128(p
, end
);
1458 if ( exportInfoSize
!= 0 ) {
1459 // print terminal info
1460 uint64_t flags
= read_uleb128(p
, end
);
1461 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1462 uint64_t ordinal
= read_uleb128(p
, end
);
1463 const char* importName
= (const char*)p
;
1467 if ( strlen(importName
) == 0 )
1468 printf("[flags=REEXPORT ordinal=%llu] ", ordinal
);
1470 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal
, importName
);
1472 else if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1473 uint64_t stub
= read_uleb128(p
, end
);
1474 uint64_t resolver
= read_uleb128(p
, end
);
1475 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub
, resolver
);
1478 uint64_t address
= read_uleb128(p
, end
);
1479 if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR
)
1480 printf("[addr=0x%06llX] ", address
);
1481 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1482 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address
);
1483 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
)
1484 printf("[flags=ABSOLUTE addr=0x%06llX] ", address
);
1486 printf("[flags=0x%llX addr=0x%06llX] ", flags
, address
);
1489 // print child edges
1490 const uint8_t childrenCount
= *p
++;
1491 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1492 const char* edgeName
= (const char*)p
;
1496 uint32_t childNodeOffet
= read_uleb128(p
, end
);
1497 printf("%s->0x%04X", edgeName
, childNodeOffet
);
1498 if ( i
< (childrenCount
-1) )
1508 template <typename A
>
1509 const uint8_t* DyldInfoPrinter
<A
>::printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p
, const uint8_t* end
, uint8_t kind
)
1511 const char* kindStr
= "??";
1513 case DYLD_CACHE_ADJ_V1_POINTER_32
:
1514 kindStr
= "32-bit pointer";
1516 case DYLD_CACHE_ADJ_V1_POINTER_64
:
1517 kindStr
= "64-bit pointer";
1519 case DYLD_CACHE_ADJ_V1_ADRP
:
1520 kindStr
= "arm64 ADRP";
1522 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+0:
1523 kindStr
= "thumb2 movt low high 4 bits=0";
1525 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+1:
1526 kindStr
= "thumb2 movt low high 4 bits=1";
1528 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+2:
1529 kindStr
= "thumb2 movt low high 4 bits=2";
1531 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+3:
1532 kindStr
= "thumb2 movt low high 4 bits=3";
1534 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+4:
1535 kindStr
= "thumb2 movt low high 4 bits=4";
1537 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+5:
1538 kindStr
= "thumb2 movt low high 4 bits=5";
1540 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+6:
1541 kindStr
= "thumb2 movt low high 4 bits=6";
1543 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+7:
1544 kindStr
= "thumb2 movt low high 4 bits=7";
1546 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+8:
1547 kindStr
= "thumb2 movt low high 4 bits=8";
1549 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+9:
1550 kindStr
= "thumb2 movt low high 4 bits=9";
1552 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+10:
1553 kindStr
= "thumb2 movt low high 4 bits=10";
1555 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+11:
1556 kindStr
= "thumb2 movt low high 4 bits=11";
1558 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+12:
1559 kindStr
= "thumb2 movt low high 4 bits=12";
1561 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+13:
1562 kindStr
= "thumb2 movt low high 4 bits=13";
1564 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+14:
1565 kindStr
= "thumb2 movt low high 4 bits=14";
1567 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+15:
1568 kindStr
= "thumb2 movt low high 4 bits=15";
1570 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+0:
1571 kindStr
= "arm movt low high 4 bits=0";
1573 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+1:
1574 kindStr
= "arm movt low high 4 bits=1";
1576 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+2:
1577 kindStr
= "arm movt low high 4 bits=2";
1579 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+3:
1580 kindStr
= "arm movt low high 4 bits=3";
1582 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+4:
1583 kindStr
= "arm movt low high 4 bits=4";
1585 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+5:
1586 kindStr
= "arm movt low high 4 bits=5";
1588 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+6:
1589 kindStr
= "arm movt low high 4 bits=6";
1591 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+7:
1592 kindStr
= "arm movt low high 4 bits=7";
1594 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+8:
1595 kindStr
= "arm movt low high 4 bits=8";
1597 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+9:
1598 kindStr
= "arm movt low high 4 bits=9";
1600 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+10:
1601 kindStr
= "arm movt low high 4 bits=10";
1603 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+11:
1604 kindStr
= "arm movt low high 4 bits=11";
1606 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+12:
1607 kindStr
= "arm movt low high 4 bits=12";
1609 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+13:
1610 kindStr
= "arm movt low high 4 bits=13";
1612 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+14:
1613 kindStr
= "arm movt low high 4 bits=14";
1615 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+15:
1616 kindStr
= "arm movt low high 4 bits=15";
1619 kindStr
= "<<unknown>>";
1621 uint64_t address
= 0;
1624 delta
= read_uleb128(p
, end
);
1626 printf("0x%0llX %s\n", address
+fBaseAddress
, kindStr
);
1632 template <typename A
>
1633 void DyldInfoPrinter
<A
>::printSharedRegionInfo()
1635 if ( (fSharedRegionInfo
== NULL
) || (fSharedRegionInfo
->datasize() == 0) ) {
1636 printf("no shared region info\n");
1639 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fSharedRegionInfo
->dataoff();
1640 const uint8_t* infoEnd
= &infoStart
[fSharedRegionInfo
->datasize()];
1641 if ( *infoStart
== DYLD_CACHE_ADJ_V2_FORMAT
) {
1643 // Whole :== <count> FromToSection+
1644 // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
1645 // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
1646 // FromOffset :== <kind> <count> <from-sect-offset-delta>
1647 const uint8_t* p
= infoStart
;
1648 uint64_t sectionCount
= read_uleb128(p
, infoEnd
);
1649 for (uint64_t i
=0; i
< sectionCount
; ++i
) {
1650 uint64_t fromSectionIndex
= read_uleb128(p
, infoEnd
);
1651 uint64_t toSectionIndex
= read_uleb128(p
, infoEnd
);
1652 uint64_t toOffsetCount
= read_uleb128(p
, infoEnd
);
1653 const macho_section
<P
>* fromSection
= fSections
[fromSectionIndex
];
1654 const macho_section
<P
>* toSection
= fSections
[toSectionIndex
];
1655 printf("from sect=%s, to sect=%s, count=%lld:\n", fromSection
->sectname(), toSection
->sectname(), toOffsetCount
);
1656 uint64_t toSectionOffset
= 0;
1657 const char* lastFromSymbol
= NULL
;
1658 for (uint64_t j
=0; j
< toOffsetCount
; ++j
) {
1659 uint64_t toSectionDelta
= read_uleb128(p
, infoEnd
);
1660 uint64_t fromOffsetCount
= read_uleb128(p
, infoEnd
);
1661 toSectionOffset
+= toSectionDelta
;
1662 for (uint64_t k
=0; k
< fromOffsetCount
; ++k
) {
1663 uint64_t kind
= read_uleb128(p
, infoEnd
);
1664 uint64_t fromSectDeltaCount
= read_uleb128(p
, infoEnd
);
1665 uint64_t fromSectionOffset
= 0;
1666 for (uint64_t l
=0; l
< fromSectDeltaCount
; ++l
) {
1667 uint64_t delta
= read_uleb128(p
, infoEnd
);
1668 fromSectionOffset
+= delta
;
1669 uint64_t symbolOffset
;
1670 const char* s
= closestSymbolNameForAddress(fromSection
->addr()+fromSectionOffset
, &symbolOffset
, fromSectionIndex
);
1671 if ( (s
!= lastFromSymbol
) && (s
!= NULL
) )
1672 printf(" %s:\n", s
);
1673 const char* toSymbol
= closestSymbolNameForAddress(toSection
->addr()+toSectionOffset
, &symbolOffset
, toSectionIndex
);
1674 printf(" from addr=0x%0llX %s to addr=0x%0llX", fromSection
->addr()+fromSectionOffset
, sharedRegionKindName(kind
), toSection
->addr()+toSectionOffset
);
1675 if ( toSymbol
!= NULL
) {
1676 if ( symbolOffset
== 0 )
1677 printf(" (%s)", toSymbol
);
1679 printf(" (%s + %lld)", toSymbol
, symbolOffset
);
1689 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
);) {
1690 uint8_t kind
= *p
++;
1691 p
= this->printSharedRegionV1InfoForEachULEB128Address(p
, infoEnd
, kind
);
1697 template <typename A
>
1698 const char* DyldInfoPrinter
<A
>::sharedRegionKindName(uint8_t kind
)
1702 return "<<unknown>>";
1703 case DYLD_CACHE_ADJ_V2_POINTER_32
:
1705 case DYLD_CACHE_ADJ_V2_POINTER_64
:
1707 case DYLD_CACHE_ADJ_V2_DELTA_32
:
1709 case DYLD_CACHE_ADJ_V2_DELTA_64
:
1711 case DYLD_CACHE_ADJ_V2_ARM64_ADRP
:
1713 case DYLD_CACHE_ADJ_V2_ARM64_OFF12
:
1715 case DYLD_CACHE_ADJ_V2_ARM64_BR26
:
1717 case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT
:
1719 case DYLD_CACHE_ADJ_V2_ARM_BR24
:
1721 case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT
:
1723 case DYLD_CACHE_ADJ_V2_THUMB_BR22
:
1725 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32
:
1731 #if SUPPORT_ARCH_arm_any
1733 void DyldInfoPrinter
<arm
>::printFunctionStartLine(uint64_t addr
)
1736 printf("0x%0llX [thumb] %s\n", (addr
& -2), symbolNameForAddress(addr
& -2));
1738 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1742 template <typename A
>
1743 void DyldInfoPrinter
<A
>::printFunctionStartLine(uint64_t addr
)
1745 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1749 template <typename A
>
1750 void DyldInfoPrinter
<A
>::printFunctionStartsInfo()
1752 if ( (fFunctionStartsInfo
== NULL
) || (fFunctionStartsInfo
->datasize() == 0) ) {
1753 printf("no function starts info\n");
1756 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fFunctionStartsInfo
->dataoff();
1757 const uint8_t* infoEnd
= &infoStart
[fFunctionStartsInfo
->datasize()];
1758 uint64_t address
= fBaseAddress
;
1759 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
); ) {
1764 uint8_t byte
= *p
++;
1765 delta
|= ((byte
& 0x7F) << shift
);
1767 if ( byte
< 0x80 ) {
1769 printFunctionStartLine(address
);
1777 template <typename A
>
1778 void DyldInfoPrinter
<A
>::printDylibsInfo()
1780 printf("attributes dependent dylibs\n");
1781 for(typename
std::vector
<const macho_dylib_command
<P
>*>::iterator it
= fDylibLoadCommands
.begin(); it
!= fDylibLoadCommands
.end(); ++it
) {
1782 const macho_dylib_command
<P
>* dylib
= *it
;
1783 const char* attribute
= "";
1784 switch ( dylib
->cmd() ) {
1785 case LC_LOAD_WEAK_DYLIB
:
1786 attribute
= "weak_import";
1788 case LC_REEXPORT_DYLIB
:
1789 attribute
= "re-export";
1791 case LC_LOAD_UPWARD_DYLIB
:
1792 attribute
= "upward";
1794 case LC_LAZY_LOAD_DYLIB
:
1795 attribute
= "lazy_load";
1801 printf(" %-12s %s\n", attribute
, dylib
->name());
1805 template <typename A
>
1806 void DyldInfoPrinter
<A
>::printDRInfo()
1808 if ( fDRInfo
== NULL
) {
1809 printf("no Designated Requirements info\n");
1812 printf("dylibs DRs\n");
1813 const uint8_t* start
= ((uint8_t*)fHeader
+ fDRInfo
->dataoff());
1814 //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
1815 typedef Security::SuperBlob
<Security::kSecCodeMagicDRList
> DRListSuperBlob
;
1816 const DRListSuperBlob
* topBlob
= (DRListSuperBlob
*)start
;
1817 if ( topBlob
->validateBlob(fDRInfo
->datasize()) ) {
1818 if ( topBlob
->count() == fDylibLoadCommands
.size() ) {
1819 for(unsigned i
=0; i
< topBlob
->count(); ++i
) {
1820 printf(" %-20s ", fDylibs
[i
]);
1821 const Security::BlobCore
* item
= topBlob
->find(i
);
1822 if ( item
!= NULL
) {
1823 const uint8_t* itemStart
= (uint8_t*)item
;
1824 const uint8_t* itemEnd
= itemStart
+ item
->length();
1825 for(const uint8_t* p
=itemStart
; p
< itemEnd
; ++p
)
1826 printf("%02X ", *p
);
1829 printf("no DR info");
1835 fprintf(stderr
, "superblob of DRs has a different number of elements than dylib load commands\n");
1839 fprintf(stderr
, "superblob of DRs invalid\n");
1848 template <typename A
>
1849 void DyldInfoPrinter
<A
>::printDataInCode()
1851 if ( fDataInCode
== NULL
) {
1852 printf("no data-in-code info\n");
1855 printf("offset length data-kind\n");
1856 const macho_data_in_code_entry
<P
>* start
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff());
1857 const macho_data_in_code_entry
<P
>* end
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff() + fDataInCode
->datasize());
1858 for (const macho_data_in_code_entry
<P
>* p
=start
; p
< end
; ++p
) {
1859 const char* kindStr
= "???";
1860 switch ( p
->kind() ) {
1865 kindStr
= "jumptable8";
1868 kindStr
= "jumptable16";
1871 kindStr
= "jumptable32";
1874 kindStr
= "jumptable32absolute";
1877 printf("0x%08X 0x%04X %s\n", p
->offset(), p
->length(), kindStr
);
1885 ppc::P::uint_t DyldInfoPrinter
<ppc
>::relocBase()
1887 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1888 return fFirstWritableSegment
->vmaddr();
1890 return fFirstSegment
->vmaddr();
1894 ppc64::P::uint_t DyldInfoPrinter
<ppc64
>::relocBase()
1896 if ( fWriteableSegmentWithAddrOver4G
)
1897 return fFirstWritableSegment
->vmaddr();
1899 return fFirstSegment
->vmaddr();
1903 x86::P::uint_t DyldInfoPrinter
<x86
>::relocBase()
1905 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1906 return fFirstWritableSegment
->vmaddr();
1908 return fFirstSegment
->vmaddr();
1912 x86_64::P::uint_t DyldInfoPrinter
<x86_64
>::relocBase()
1914 return fFirstWritableSegment
->vmaddr();
1917 #if SUPPORT_ARCH_arm_any
1919 arm::P::uint_t DyldInfoPrinter
<arm
>::relocBase()
1921 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1922 return fFirstWritableSegment
->vmaddr();
1924 return fFirstSegment
->vmaddr();
1928 #if SUPPORT_ARCH_arm64
1930 arm64::P::uint_t DyldInfoPrinter
<arm64
>::relocBase()
1932 return fFirstWritableSegment
->vmaddr();
1937 const char* DyldInfoPrinter
<ppc
>::relocTypeName(uint8_t r_type
)
1939 if ( r_type
== GENERIC_RELOC_VANILLA
)
1946 const char* DyldInfoPrinter
<ppc64
>::relocTypeName(uint8_t r_type
)
1948 if ( r_type
== GENERIC_RELOC_VANILLA
)
1955 const char* DyldInfoPrinter
<x86
>::relocTypeName(uint8_t r_type
)
1957 if ( r_type
== GENERIC_RELOC_VANILLA
)
1959 else if ( r_type
== GENERIC_RELOC_PB_LA_PTR
)
1960 return "pb pointer";
1966 const char* DyldInfoPrinter
<x86_64
>::relocTypeName(uint8_t r_type
)
1968 if ( r_type
== X86_64_RELOC_UNSIGNED
)
1974 #if SUPPORT_ARCH_arm_any
1976 const char* DyldInfoPrinter
<arm
>::relocTypeName(uint8_t r_type
)
1978 if ( r_type
== ARM_RELOC_VANILLA
)
1980 else if ( r_type
== ARM_RELOC_PB_LA_PTR
)
1981 return "pb pointer";
1987 #if SUPPORT_ARCH_arm64
1989 const char* DyldInfoPrinter
<arm64
>::relocTypeName(uint8_t r_type
)
1991 if ( r_type
== ARM64_RELOC_UNSIGNED
)
1997 template <typename A
>
1998 void DyldInfoPrinter
<A
>::printRelocRebaseInfo()
2000 if ( fDynamicSymbolTable
== NULL
) {
2001 printf("no classic dynamic symbol table");
2004 printf("rebase information (from local relocation records and indirect symbol table):\n");
2005 printf("segment section address type\n");
2006 // walk all local relocations
2007 pint_t rbase
= relocBase();
2008 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->locreloff());
2009 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nlocrel()];
2010 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2011 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
2012 pint_t addr
= reloc
->r_address() + rbase
;
2013 uint8_t segIndex
= segmentIndexForAddress(addr
);
2014 const char* typeName
= relocTypeName(reloc
->r_type());
2015 const char* segName
= segmentName(segIndex
);
2016 const char* sectName
= sectionName(segIndex
, addr
);
2017 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
2020 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
2021 pint_t addr
= sreloc
->r_address() + rbase
;
2022 uint8_t segIndex
= segmentIndexForAddress(addr
);
2023 const char* typeName
= relocTypeName(sreloc
->r_type());
2024 const char* segName
= segmentName(segIndex
);
2025 const char* sectName
= sectionName(segIndex
, addr
);
2026 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
2029 // look for local non-lazy-pointers
2030 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2031 uint8_t segIndex
= 0;
2032 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
, ++segIndex
) {
2033 const macho_segment_command
<P
>* segCmd
= *segit
;
2034 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2035 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2036 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2037 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2038 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2039 uint32_t indirectOffset
= sect
->reserved1();
2040 uint32_t count
= sect
->size() / sizeof(pint_t
);
2041 for (uint32_t i
=0; i
< count
; ++i
) {
2042 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2043 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
2044 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2045 const char* typeName
= "pointer";
2046 const char* segName
= segmentName(segIndex
);
2047 const char* sectName
= sectionName(segIndex
, addr
);
2048 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
2058 template <typename A
>
2059 void DyldInfoPrinter
<A
>::printSymbolTableExportInfo()
2061 if ( fDynamicSymbolTable
== NULL
) {
2062 printf("no classic dynamic symbol table");
2065 printf("export information (from symbol table):\n");
2066 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
2067 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
2068 const char* flags
= "";
2069 if ( sym
->n_desc() & N_WEAK_DEF
)
2070 flags
= "[weak_def] ";
2072 if ( sym
->n_desc() & N_ARM_THUMB_DEF
)
2074 printf("0x%08llX %s%s\n", sym
->n_value()+thumb
, flags
, &fStrings
[sym
->n_strx()]);
2079 template <typename A
>
2080 const char* DyldInfoPrinter
<A
>::closestSymbolNameForAddress(uint64_t addr
, uint64_t* offset
, uint8_t sectIndex
)
2082 const macho_nlist
<P
>* bestSymbol
= NULL
;
2083 if ( fDynamicSymbolTable
!= NULL
) {
2084 // find closest match in globals
2085 const macho_nlist
<P
>* const globalsStart
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()];
2086 const macho_nlist
<P
>* const globalsEnd
= &globalsStart
[fDynamicSymbolTable
->nextdefsym()];
2087 for (const macho_nlist
<P
>* s
= globalsStart
; s
< globalsEnd
; ++s
) {
2088 if ( (s
->n_type() & N_TYPE
) == N_SECT
) {
2089 if ( (s
->n_value() <= addr
) && ((s
->n_sect() == sectIndex
) || (sectIndex
==0)) ) {
2090 if ( (bestSymbol
== NULL
) || (bestSymbol
->n_value() < s
->n_value()) )
2096 // find closest match in locals
2097 const macho_nlist
<P
>* const localsStart
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()];
2098 const macho_nlist
<P
>* const localsEnd
= &localsStart
[fDynamicSymbolTable
->nlocalsym()];
2099 for (const macho_nlist
<P
>* s
= localsStart
; s
< localsEnd
; ++s
) {
2100 if ( ((s
->n_type() & N_TYPE
) == N_SECT
) && ((s
->n_type() & N_STAB
) == 0) ) {
2101 if ( (s
->n_value() <= addr
) && ((s
->n_sect() == sectIndex
) || (sectIndex
==0)) ) {
2102 if ( (bestSymbol
== NULL
) || (bestSymbol
->n_value() < s
->n_value()) )
2109 // find closest match in locals
2110 const macho_nlist
<P
>* const allStart
= &fSymbols
[0];
2111 const macho_nlist
<P
>* const allEnd
= &fSymbols
[fSymbolCount
];
2112 for (const macho_nlist
<P
>* s
= allStart
; s
< allEnd
; ++s
) {
2113 if ( ((s
->n_type() & N_TYPE
) == N_SECT
) && ((s
->n_type() & N_STAB
) == 0) ) {
2114 if ( (s
->n_value() <= addr
) && ((s
->n_sect() == sectIndex
) || (sectIndex
==0)) ) {
2115 if ( (bestSymbol
== NULL
) || (bestSymbol
->n_value() < s
->n_value()) )
2121 if ( bestSymbol
!= NULL
) {
2122 *offset
= addr
- bestSymbol
->n_value();
2123 return &fStrings
[bestSymbol
->n_strx()];
2129 template <typename A
>
2130 const char* DyldInfoPrinter
<A
>::symbolNameForAddress(uint64_t addr
)
2133 const char* s
= closestSymbolNameForAddress(addr
, &offset
);
2134 if ( (offset
== 0) && (s
!= NULL
) )
2139 template <typename A
>
2140 void DyldInfoPrinter
<A
>::printClassicBindingInfo()
2142 if ( fDynamicSymbolTable
== NULL
) {
2143 printf("no classic dynamic symbol table");
2146 printf("binding information (from relocations and indirect symbol table):\n");
2147 printf("segment section address type weak addend dylib symbol\n");
2148 // walk all external relocations
2149 pint_t rbase
= relocBase();
2150 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->extreloff());
2151 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
2152 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2153 pint_t addr
= reloc
->r_address() + rbase
;
2154 uint32_t symbolIndex
= reloc
->r_symbolnum();
2155 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2156 const char* symbolName
= &fStrings
[sym
->n_strx()];
2157 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
2158 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2159 uint8_t segIndex
= segmentIndexForAddress(addr
);
2160 const char* typeName
= relocTypeName(reloc
->r_type());
2161 const char* segName
= segmentName(segIndex
);
2162 const char* sectName
= sectionName(segIndex
, addr
);
2163 const pint_t
* addressMapped
= mappedAddressForVMAddress(addr
);
2164 int64_t addend
= P::getP(*addressMapped
);
2165 if ( fHeader
->flags() & MH_PREBOUND
) {
2166 // In prebound binaries the content is already pointing to the target.
2167 // To get the addend requires subtracting out the base address it was prebound to.
2168 addend
-= sym
->n_value();
2170 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
2171 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
2173 // look for non-lazy pointers
2174 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2175 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2176 const macho_segment_command
<P
>* segCmd
= *segit
;
2177 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2178 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2179 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2180 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2181 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2182 uint32_t indirectOffset
= sect
->reserved1();
2183 uint32_t count
= sect
->size() / sizeof(pint_t
);
2184 for (uint32_t i
=0; i
< count
; ++i
) {
2185 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2186 if ( symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
2187 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2188 const char* symbolName
= &fStrings
[sym
->n_strx()];
2189 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
2190 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2191 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2192 uint8_t segIndex
= segmentIndexForAddress(addr
);
2193 const char* typeName
= "pointer";
2194 const char* segName
= segmentName(segIndex
);
2195 const char* sectName
= sectionName(segIndex
, addr
);
2197 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
2198 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
2208 template <typename A
>
2209 void DyldInfoPrinter
<A
>::printClassicLazyBindingInfo()
2211 if ( fDynamicSymbolTable
== NULL
) {
2212 printf("no classic dynamic symbol table");
2215 printf("lazy binding information (from section records and indirect symbol table):\n");
2216 printf("segment section address index dylib symbol\n");
2217 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2218 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2219 const macho_segment_command
<P
>* segCmd
= *segit
;
2220 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2221 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2222 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2223 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2224 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2225 uint32_t indirectOffset
= sect
->reserved1();
2226 uint32_t count
= sect
->size() / sizeof(pint_t
);
2227 for (uint32_t i
=0; i
< count
; ++i
) {
2228 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2229 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2230 const char* symbolName
= &fStrings
[sym
->n_strx()];
2231 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2232 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2233 uint8_t segIndex
= segmentIndexForAddress(addr
);
2234 const char* segName
= segmentName(segIndex
);
2235 const char* sectName
= sectionName(segIndex
, addr
);
2236 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2239 else if ( (type
== S_SYMBOL_STUBS
) && (((sect
->flags() & S_ATTR_SELF_MODIFYING_CODE
) != 0)) && (sect
->reserved2() == 5) ) {
2240 // i386 self-modifying stubs
2241 uint32_t indirectOffset
= sect
->reserved1();
2242 uint32_t count
= sect
->size() / 5;
2243 for (uint32_t i
=0; i
< count
; ++i
) {
2244 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2245 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
2246 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2247 const char* symbolName
= &fStrings
[sym
->n_strx()];
2248 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2249 pint_t addr
= sect
->addr() + i
*5;
2250 uint8_t segIndex
= segmentIndexForAddress(addr
);
2251 const char* segName
= segmentName(segIndex
);
2252 const char* sectName
= sectionName(segIndex
, addr
);
2253 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2262 static void dump(const char* path
)
2264 struct stat stat_buf
;
2267 int fd
= ::open(path
, O_RDONLY
, 0);
2269 throw "cannot open file";
2270 if ( ::fstat(fd
, &stat_buf
) != 0 )
2271 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
2272 uint32_t length
= stat_buf
.st_size
;
2273 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
2274 if ( p
== ((uint8_t*)(-1)) )
2275 throw "cannot map file";
2277 const mach_header
* mh
= (mach_header
*)p
;
2278 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2279 const struct fat_header
* fh
= (struct fat_header
*)p
;
2280 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
2281 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2282 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2283 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
2284 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
2285 cpu_type_t cpusubtype
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
);
2286 if ( ((cputype
== sPreferredArch
)
2287 && ((sPreferredSubArch
==0) || (sPreferredSubArch
==cpusubtype
)))
2288 || (sPreferredArch
== 0) ) {
2290 case CPU_TYPE_POWERPC
:
2291 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
2292 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2294 throw "in universal file, ppc slice does not contain ppc mach-o";
2297 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
2298 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2300 throw "in universal file, i386 slice does not contain i386 mach-o";
2302 case CPU_TYPE_POWERPC64
:
2303 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
2304 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2306 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
2308 case CPU_TYPE_X86_64
:
2309 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
2310 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2312 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
2314 #if SUPPORT_ARCH_arm_any
2316 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
2317 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2319 throw "in universal file, arm slice does not contain arm mach-o";
2322 #if SUPPORT_ARCH_arm64
2323 case CPU_TYPE_ARM64
:
2324 if ( DyldInfoPrinter
<arm64
>::validFile(p
+ offset
) )
2325 DyldInfoPrinter
<arm64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2327 throw "in universal file, arm64 slice does not contain arm mach-o";
2331 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
2336 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
2337 DyldInfoPrinter
<x86
>::make(p
, length
, path
, false);
2339 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
2340 DyldInfoPrinter
<ppc
>::make(p
, length
, path
, false);
2342 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
2343 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
, false);
2345 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
2346 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
, false);
2348 #if SUPPORT_ARCH_arm_any
2349 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
2350 DyldInfoPrinter
<arm
>::make(p
, length
, path
, false);
2353 #if SUPPORT_ARCH_arm64
2354 else if ( DyldInfoPrinter
<arm64
>::validFile(p
) ) {
2355 DyldInfoPrinter
<arm64
>::make(p
, length
, path
, false);
2359 throw "not a known file type";
2362 catch (const char* msg
) {
2363 throwf("%s in %s", msg
, path
);
2369 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
2370 "\t-dylibs print dependent dylibs\n"
2371 "\t-dr print dependent dylibs and show any recorded DR info\n"
2372 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
2373 "\t-bind print addresses dyld will set based on symbolic lookups\n"
2374 "\t-weak_bind print symbols which dyld must coalesce\n"
2375 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
2376 "\t-export print addresses of all symbols this file exports\n"
2377 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
2378 "\t-function_starts print table of function start addresses\n"
2379 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
2380 "\t-data_in_code print any data-in-code information\n"
2385 int main(int argc
, const char* argv
[])
2393 std::vector
<const char*> files
;
2394 for(int i
=1; i
< argc
; ++i
) {
2395 const char* arg
= argv
[i
];
2396 if ( arg
[0] == '-' ) {
2397 if ( strcmp(arg
, "-arch") == 0 ) {
2398 const char* arch
= ++i
<argc
? argv
[i
]: "";
2399 if ( strcmp(arch
, "ppc64") == 0 )
2400 sPreferredArch
= CPU_TYPE_POWERPC64
;
2401 else if ( strcmp(arch
, "ppc") == 0 )
2402 sPreferredArch
= CPU_TYPE_POWERPC
;
2403 else if ( strcmp(arch
, "i386") == 0 )
2404 sPreferredArch
= CPU_TYPE_I386
;
2405 else if ( strcmp(arch
, "x86_64") == 0 )
2406 sPreferredArch
= CPU_TYPE_X86_64
;
2407 #if SUPPORT_ARCH_arm64
2408 else if ( strcmp(arch
, "arm64") == 0 )
2409 sPreferredArch
= CPU_TYPE_ARM64
;
2413 throw "-arch missing architecture name";
2415 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
2416 if ( strcmp(t
->archName
,arch
) == 0 ) {
2417 sPreferredArch
= t
->cpuType
;
2419 sPreferredSubArch
= t
->cpuSubType
;
2425 throwf("unknown architecture %s", arch
);
2428 else if ( strcmp(arg
, "-rebase") == 0 ) {
2431 else if ( strcmp(arg
, "-bind") == 0 ) {
2434 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
2435 printWeakBind
= true;
2437 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
2438 printLazyBind
= true;
2440 else if ( strcmp(arg
, "-export") == 0 ) {
2443 else if ( strcmp(arg
, "-opcodes") == 0 ) {
2444 printOpcodes
= true;
2446 else if ( strcmp(arg
, "-export_dot") == 0 ) {
2447 printExportGraph
= true;
2449 else if ( strcmp(arg
, "-export_trie_nodes") == 0 ) {
2450 printExportNodes
= true;
2452 else if ( strcmp(arg
, "-shared_region") == 0 ) {
2453 printSharedRegion
= true;
2455 else if ( strcmp(arg
, "-function_starts") == 0 ) {
2456 printFunctionStarts
= true;
2458 else if ( strcmp(arg
, "-dylibs") == 0 ) {
2461 else if ( strcmp(arg
, "-dr") == 0 ) {
2464 else if ( strcmp(arg
, "-data_in_code") == 0 ) {
2465 printDataCode
= true;
2468 throwf("unknown option: %s\n", arg
);
2472 files
.push_back(arg
);
2475 if ( files
.size() == 0 )
2477 if ( files
.size() == 1 ) {
2481 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
2482 printf("\n%s:\n", *it
);
2487 catch (const char* msg
) {
2488 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);