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()) {
245 #if SUPPORT_ARCH_arm_any
247 bool DyldInfoPrinter
<arm
>::validFile(const uint8_t* fileContent
)
249 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
250 if ( header
->magic() != MH_MAGIC
)
252 if ( header
->cputype() != CPU_TYPE_ARM
)
254 switch (header
->filetype()) {
267 #if SUPPORT_ARCH_arm64
269 bool DyldInfoPrinter
<arm64
>::validFile(const uint8_t* fileContent
)
271 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
272 if ( header
->magic() != MH_MAGIC_64
)
274 if ( header
->cputype() != CPU_TYPE_ARM64
)
276 switch (header
->filetype()) {
289 template <typename A
>
290 DyldInfoPrinter
<A
>::DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
291 : fHeader(NULL
), fLength(fileLength
),
292 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fInfo(NULL
),
293 fSharedRegionInfo(NULL
), fFunctionStartsInfo(NULL
), fDataInCode(NULL
), fDRInfo(NULL
),
294 fBaseAddress(0), fDynamicSymbolTable(NULL
), fFirstSegment(NULL
), fFirstWritableSegment(NULL
),
295 fWriteableSegmentWithAddrOver4G(false)
298 if ( ! validFile(fileContent
) )
299 throw "not a mach-o file that can be checked";
301 fPath
= strdup(path
);
302 fHeader
= (const macho_header
<P
>*)fileContent
;
304 fMachHeaderPseudoSection
.set_segname("__TEXT");
305 fMachHeaderPseudoSection
.set_sectname("");
306 fMachHeaderPseudoSection
.set_addr(0);
307 fSections
.push_back(&fMachHeaderPseudoSection
);
310 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
311 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
312 const uint32_t cmd_count
= fHeader
->ncmds();
313 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
314 const macho_load_command
<P
>* cmd
= cmds
;
315 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
316 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
317 if ( endOfCmd
> endOfLoadCommands
)
318 throwf("load command #%d extends beyond the end of the load commands", i
);
319 if ( endOfCmd
> endOfFile
)
320 throwf("load command #%d extends beyond the end of the file", i
);
321 switch ( cmd
->cmd() ) {
323 case LC_DYLD_INFO_ONLY
:
324 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
326 case macho_segment_command
<P
>::CMD
:
328 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
329 fSegments
.push_back(segCmd
);
330 if ( (segCmd
->fileoff() == 0) && (segCmd
->filesize() != 0) )
331 fBaseAddress
= segCmd
->vmaddr();
332 if ( fFirstSegment
== NULL
)
333 fFirstSegment
= segCmd
;
334 if ( (segCmd
->initprot() & VM_PROT_WRITE
) != 0 ) {
335 if ( fFirstWritableSegment
== NULL
)
336 fFirstWritableSegment
= segCmd
;
337 if ( segCmd
->vmaddr() > 0x100000000ULL
)
338 fWriteableSegmentWithAddrOver4G
= true;
340 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
341 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
342 for(const macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
)
343 fSections
.push_back(sect
);
347 case LC_LOAD_WEAK_DYLIB
:
348 case LC_REEXPORT_DYLIB
:
349 case LC_LOAD_UPWARD_DYLIB
:
350 case LC_LAZY_LOAD_DYLIB
:
352 const macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
353 fDylibLoadCommands
.push_back(dylib
);
354 const char* lastSlash
= strrchr(dylib
->name(), '/');
355 const char* leafName
= (lastSlash
!= NULL
) ? lastSlash
+1 : dylib
->name();
356 const char* firstDot
= strchr(leafName
, '.');
357 if ( firstDot
!= NULL
) {
358 char* t
= strdup(leafName
);
359 t
[firstDot
-leafName
] = '\0';
360 fDylibs
.push_back(t
);
363 fDylibs
.push_back(leafName
);
368 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
372 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
373 fSymbolCount
= symtab
->nsyms();
374 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
375 fStrings
= (char*)fHeader
+ symtab
->stroff();
376 fStringsEnd
= fStrings
+ symtab
->strsize();
379 case LC_SEGMENT_SPLIT_INFO
:
380 fSharedRegionInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
382 case LC_FUNCTION_STARTS
:
383 fFunctionStartsInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
385 case LC_DATA_IN_CODE
:
386 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
388 case LC_DYLIB_CODE_SIGN_DRS
:
389 fDRInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
392 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
396 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
397 if ( (cpu_type_t
)fHeader
->cputype() == t
->cpuType
) {
398 if ( t
->isSubType
&& ((cpu_subtype_t
)fHeader
->cpusubtype() != t
->cpuSubType
) )
400 printf("for arch %s:\n", t
->archName
);
409 printRelocRebaseInfo();
415 printClassicBindingInfo();
418 printWeakBindingInfo();
419 if ( printLazyBind
) {
421 printLazyBindingInfo();
423 printClassicLazyBindingInfo();
429 printSymbolTableExportInfo();
431 if ( printOpcodes
) {
432 printRebaseInfoOpcodes();
433 printBindingInfoOpcodes(false);
434 printBindingInfoOpcodes(true);
435 printLazyBindingOpcodes();
437 if ( printExportGraph
)
438 printExportInfoGraph();
439 if ( printExportNodes
)
440 printExportInfoNodes();
441 if ( printSharedRegion
)
442 printSharedRegionInfo();
443 if ( printFunctionStarts
)
444 printFunctionStartsInfo();
453 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
459 throwf("malformed uleb128");
461 uint64_t slice
= *p
& 0x7f;
463 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
464 throwf("uleb128 too big");
466 result
|= (slice
<< bit
);
474 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
481 throwf("malformed sleb128");
483 result
|= (((int64_t)(byte
& 0x7f)) << bit
);
485 } while (byte
& 0x80);
486 // sign extend negative numbers
487 if ( (byte
& 0x40) != 0 )
488 result
|= (-1LL) << bit
;
493 template <typename A
>
494 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
497 case REBASE_TYPE_POINTER
:
499 case REBASE_TYPE_TEXT_ABSOLUTE32
:
501 case REBASE_TYPE_TEXT_PCREL32
:
504 return "!!unknown!!";
508 template <typename A
>
509 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
512 case BIND_TYPE_POINTER
:
514 case BIND_TYPE_TEXT_ABSOLUTE32
:
516 case BIND_TYPE_TEXT_PCREL32
:
519 return "!!unknown!!";
523 template <typename A
>
524 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
526 if ( segIndex
> fSegments
.size() )
527 throw "segment index out of range";
528 return fSegments
[segIndex
]->vmaddr();
531 template <typename A
>
532 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
534 if ( segIndex
> fSegments
.size() )
535 throw "segment index out of range";
536 return fSegments
[segIndex
]->segname();
539 template <typename A
>
540 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
542 if ( segIndex
> fSegments
.size() )
543 throw "segment index out of range";
544 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
545 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
546 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
547 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
548 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
549 if ( strlen(sect
->sectname()) > 15 ) {
550 static char temp
[18];
551 strlcpy(temp
, sect
->sectname(), 17);
555 return sect
->sectname();
562 template <typename A
>
563 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
565 static char buffer
[64];
566 strcpy(buffer
, segmentName(segIndex
));
568 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
569 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
570 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
571 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
572 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
573 // section name may not be zero terminated
574 char* end
= &buffer
[strlen(buffer
)];
575 strlcpy(end
, sect
->sectname(), 16);
582 template <typename A
>
583 uint8_t DyldInfoPrinter
<A
>::segmentIndexForAddress(pint_t address
)
585 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
586 if ( (fSegments
[i
]->vmaddr() <= address
) && (address
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
590 throwf("address 0x%llX is not in any segment", (uint64_t)address
);
593 template <typename A
>
594 typename
A::P::uint_t
* DyldInfoPrinter
<A
>::mappedAddressForVMAddress(pint_t vmaddress
)
596 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
597 if ( (fSegments
[i
]->vmaddr() <= vmaddress
) && (vmaddress
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
598 unsigned long offsetInMappedFile
= fSegments
[i
]->fileoff()+vmaddress
-fSegments
[i
]->vmaddr();
599 return (pint_t
*)((uint8_t*)fHeader
+ offsetInMappedFile
);
602 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress
);
605 template <typename A
>
606 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
608 switch ( libraryOrdinal
) {
609 case BIND_SPECIAL_DYLIB_SELF
:
611 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
612 return "main-executable";
613 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
614 return "flat-namespace";
616 if ( libraryOrdinal
< BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
617 throw "unknown special ordinal";
618 if ( libraryOrdinal
> (int)fDylibs
.size() )
619 throw "libraryOrdinal out of range";
620 return fDylibs
[libraryOrdinal
-1];
623 template <typename A
>
624 const char* DyldInfoPrinter
<A
>::classicOrdinalName(int libraryOrdinal
)
626 if ( (fHeader
->flags() & MH_TWOLEVEL
) == 0 )
627 return "flat-namespace";
628 switch ( libraryOrdinal
) {
629 case SELF_LIBRARY_ORDINAL
:
631 case EXECUTABLE_ORDINAL
:
632 return "main-executable";
633 case DYNAMIC_LOOKUP_ORDINAL
:
634 return "flat-namespace";
636 if ( libraryOrdinal
> (int)fDylibs
.size() )
637 throw "libraryOrdinal out of range";
638 return fDylibs
[libraryOrdinal
-1];
641 template <typename A
>
642 void DyldInfoPrinter
<A
>::printRebaseInfo()
644 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
645 printf("no compressed rebase info\n");
648 printf("rebase information (from compressed dyld info):\n");
649 printf("segment section address type\n");
651 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
652 const uint8_t* end
= &p
[fInfo
->rebase_size()];
655 uint64_t segOffset
= 0;
659 pint_t segStartAddr
= 0;
660 const char* segName
= "??";
661 const char* typeName
= "??";
663 while ( !done
&& (p
< end
) ) {
664 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
665 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
668 case REBASE_OPCODE_DONE
:
671 case REBASE_OPCODE_SET_TYPE_IMM
:
673 typeName
= rebaseTypeName(type
);
675 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
676 segIndex
= immediate
;
677 segStartAddr
= segStartAddress(segIndex
);
678 segName
= segmentName(segIndex
);
679 segOffset
= read_uleb128(p
, end
);
681 case REBASE_OPCODE_ADD_ADDR_ULEB
:
682 segOffset
+= read_uleb128(p
, end
);
684 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
685 segOffset
+= immediate
*sizeof(pint_t
);
687 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
688 for (int i
=0; i
< immediate
; ++i
) {
689 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
690 segOffset
+= sizeof(pint_t
);
693 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
694 count
= read_uleb128(p
, end
);
695 for (uint32_t i
=0; i
< count
; ++i
) {
696 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
697 segOffset
+= sizeof(pint_t
);
700 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
701 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
702 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
704 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
705 count
= read_uleb128(p
, end
);
706 skip
= read_uleb128(p
, end
);
707 for (uint32_t i
=0; i
< count
; ++i
) {
708 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
709 segOffset
+= skip
+ sizeof(pint_t
);
713 throwf("bad rebase opcode %d", *p
);
722 template <typename A
>
723 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
725 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
726 printf("no compressed rebase info\n");
729 printf("rebase opcodes:\n");
730 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
731 const uint8_t* end
= &start
[fInfo
->rebase_size()];
732 const uint8_t* p
= start
;
735 uint64_t address
= fBaseAddress
;
738 unsigned int segmentIndex
;
740 while ( !done
&& (p
< end
) ) {
741 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
742 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
743 uint32_t opcodeOffset
= p
-start
;
746 case REBASE_OPCODE_DONE
:
748 printf("0x%04X REBASE_OPCODE_DONE()\n", opcodeOffset
);
750 case REBASE_OPCODE_SET_TYPE_IMM
:
752 printf("0x%04X REBASE_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
754 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
755 segmentIndex
= immediate
;
756 address
= read_uleb128(p
, end
);
757 printf("0x%04X REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
759 case REBASE_OPCODE_ADD_ADDR_ULEB
:
760 address
= read_uleb128(p
, end
);
761 printf("0x%04X REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", opcodeOffset
, address
);
763 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
764 address
= immediate
*sizeof(pint_t
);
765 printf("0x%04X REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", opcodeOffset
, address
);
767 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
768 printf("0x%04X REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", opcodeOffset
, immediate
);
770 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
771 count
= read_uleb128(p
, end
);
772 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", opcodeOffset
, count
);
774 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
775 skip
= read_uleb128(p
, end
) + sizeof(pint_t
);
776 printf("0x%04X REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", opcodeOffset
, skip
);
778 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
779 count
= read_uleb128(p
, end
);
780 skip
= read_uleb128(p
, end
);
781 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", opcodeOffset
, count
, skip
);
784 throwf("bad rebase opcode %d", *p
);
796 template <typename A
>
797 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
799 if ( fInfo
== NULL
) {
800 printf("no compressed binding info\n");
802 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
803 printf("no compressed binding info\n");
805 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
806 printf("no compressed weak binding info\n");
809 const uint8_t* start
;
812 printf("weak binding opcodes:\n");
813 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
814 end
= &start
[fInfo
->weak_bind_size()];
817 printf("binding opcodes:\n");
818 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
819 end
= &start
[fInfo
->bind_size()];
821 const uint8_t* p
= start
;
824 uint64_t address
= fBaseAddress
;
825 const char* symbolName
= NULL
;
826 int libraryOrdinal
= 0;
828 uint32_t segmentIndex
= 0;
832 while ( !done
&& (p
< end
) ) {
833 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
834 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
835 uint32_t opcodeOffset
= p
-start
;
838 case BIND_OPCODE_DONE
:
840 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
842 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
843 libraryOrdinal
= immediate
;
844 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
846 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
847 libraryOrdinal
= read_uleb128(p
, end
);
848 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
850 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
851 // the special ordinals are negative numbers
852 if ( immediate
== 0 )
855 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
856 libraryOrdinal
= signExtended
;
858 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
860 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
862 symbolName
= (char*)p
;
866 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
868 case BIND_OPCODE_SET_TYPE_IMM
:
870 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
872 case BIND_OPCODE_SET_ADDEND_SLEB
:
873 addend
= read_sleb128(p
, end
);
874 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
876 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
877 segmentIndex
= immediate
;
878 address
= read_uleb128(p
, end
);
879 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
881 case BIND_OPCODE_ADD_ADDR_ULEB
:
882 skip
= read_uleb128(p
, end
);
883 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
885 case BIND_OPCODE_DO_BIND
:
886 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
888 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
889 skip
= read_uleb128(p
, end
);
890 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
892 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
893 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
894 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
896 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
897 count
= read_uleb128(p
, end
);
898 skip
= read_uleb128(p
, end
);
899 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
902 throwf("unknown bind opcode %d", *p
);
911 template <typename A
>
912 void DyldInfoPrinter
<A
>::printBindingInfo()
914 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
915 printf("no compressed binding info\n");
918 printf("bind information:\n");
919 printf("segment section address type addend dylib symbol\n");
920 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->bind_off();
921 const uint8_t* end
= &p
[fInfo
->bind_size()];
924 uint8_t segIndex
= 0;
925 uint64_t segOffset
= 0;
926 const char* symbolName
= NULL
;
927 const char* fromDylib
= "??";
928 int libraryOrdinal
= 0;
932 pint_t segStartAddr
= 0;
933 const char* segName
= "??";
934 const char* typeName
= "??";
935 const char* weak_import
= "";
937 while ( !done
&& (p
< end
) ) {
938 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
939 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
942 case BIND_OPCODE_DONE
:
945 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
946 libraryOrdinal
= immediate
;
947 fromDylib
= ordinalName(libraryOrdinal
);
949 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
950 libraryOrdinal
= read_uleb128(p
, end
);
951 fromDylib
= ordinalName(libraryOrdinal
);
953 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
954 // the special ordinals are negative numbers
955 if ( immediate
== 0 )
958 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
959 libraryOrdinal
= signExtended
;
961 fromDylib
= ordinalName(libraryOrdinal
);
963 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
964 symbolName
= (char*)p
;
968 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
969 weak_import
= " (weak import)";
973 case BIND_OPCODE_SET_TYPE_IMM
:
975 typeName
= bindTypeName(type
);
977 case BIND_OPCODE_SET_ADDEND_SLEB
:
978 addend
= read_sleb128(p
, end
);
980 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
981 segIndex
= immediate
;
982 segStartAddr
= segStartAddress(segIndex
);
983 segName
= segmentName(segIndex
);
984 segOffset
= read_uleb128(p
, end
);
986 case BIND_OPCODE_ADD_ADDR_ULEB
:
987 segOffset
+= read_uleb128(p
, end
);
989 case BIND_OPCODE_DO_BIND
:
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
+= sizeof(pint_t
);
993 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
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
+= read_uleb128(p
, end
) + sizeof(pint_t
);
997 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
998 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
999 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1001 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1002 count
= read_uleb128(p
, end
);
1003 skip
= read_uleb128(p
, end
);
1004 for (uint32_t i
=0; i
< count
; ++i
) {
1005 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
1006 segOffset
+= skip
+ sizeof(pint_t
);
1010 throwf("bad bind opcode %d", *p
);
1017 template <typename A
>
1018 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
1020 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
1021 printf("no weak binding\n");
1024 printf("weak binding information:\n");
1025 printf("segment section address type addend symbol\n");
1026 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
1027 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
1030 uint8_t segIndex
= 0;
1031 uint64_t segOffset
= 0;
1032 const char* symbolName
= NULL
;
1036 pint_t segStartAddr
= 0;
1037 const char* segName
= "??";
1038 const char* typeName
= "??";
1040 while ( !done
&& (p
< end
) ) {
1041 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1042 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1045 case BIND_OPCODE_DONE
:
1048 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1049 symbolName
= (char*)p
;
1053 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
1054 printf(" strong %s\n", symbolName
);
1056 case BIND_OPCODE_SET_TYPE_IMM
:
1058 typeName
= bindTypeName(type
);
1060 case BIND_OPCODE_SET_ADDEND_SLEB
:
1061 addend
= read_sleb128(p
, end
);
1063 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1064 segIndex
= immediate
;
1065 segStartAddr
= segStartAddress(segIndex
);
1066 segName
= segmentName(segIndex
);
1067 segOffset
= read_uleb128(p
, end
);
1069 case BIND_OPCODE_ADD_ADDR_ULEB
:
1070 segOffset
+= read_uleb128(p
, end
);
1072 case BIND_OPCODE_DO_BIND
:
1073 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1074 segOffset
+= sizeof(pint_t
);
1076 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1077 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1078 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1080 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1081 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1082 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1084 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1085 count
= read_uleb128(p
, end
);
1086 skip
= read_uleb128(p
, end
);
1087 for (uint32_t i
=0; i
< count
; ++i
) {
1088 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1089 segOffset
+= skip
+ sizeof(pint_t
);
1093 throwf("unknown weak bind opcode %d", *p
);
1101 template <typename A
>
1102 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
1104 if ( fInfo
== NULL
) {
1105 printf("no compressed dyld info\n");
1107 else if ( fInfo
->lazy_bind_off() == 0 ) {
1108 printf("no compressed lazy binding info\n");
1111 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1112 printf("segment section address index dylib symbol\n");
1113 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1114 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1116 uint8_t type
= BIND_TYPE_POINTER
;
1117 uint8_t segIndex
= 0;
1118 uint64_t segOffset
= 0;
1119 const char* symbolName
= NULL
;
1120 const char* fromDylib
= "??";
1121 int libraryOrdinal
= 0;
1123 uint32_t lazy_offset
= 0;
1124 pint_t segStartAddr
= 0;
1125 const char* segName
= "??";
1126 const char* typeName
= "??";
1127 const char* weak_import
= "";
1128 for (const uint8_t* p
=start
; p
< end
; ) {
1129 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1130 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1133 case BIND_OPCODE_DONE
:
1134 lazy_offset
= p
-start
;
1136 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1137 libraryOrdinal
= immediate
;
1138 fromDylib
= ordinalName(libraryOrdinal
);
1140 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1141 libraryOrdinal
= read_uleb128(p
, end
);
1142 fromDylib
= ordinalName(libraryOrdinal
);
1144 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1145 // the special ordinals are negative numbers
1146 if ( immediate
== 0 )
1149 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1150 libraryOrdinal
= signExtended
;
1152 fromDylib
= ordinalName(libraryOrdinal
);
1154 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1155 symbolName
= (char*)p
;
1159 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
1160 weak_import
= " (weak import)";
1164 case BIND_OPCODE_SET_TYPE_IMM
:
1166 typeName
= bindTypeName(type
);
1168 case BIND_OPCODE_SET_ADDEND_SLEB
:
1169 addend
= read_sleb128(p
, end
);
1171 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1172 segIndex
= immediate
;
1173 segStartAddr
= segStartAddress(segIndex
);
1174 segName
= segmentName(segIndex
);
1175 segOffset
= read_uleb128(p
, end
);
1177 case BIND_OPCODE_ADD_ADDR_ULEB
:
1178 segOffset
+= read_uleb128(p
, end
);
1180 case BIND_OPCODE_DO_BIND
:
1181 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
, weak_import
);
1182 segOffset
+= sizeof(pint_t
);
1185 throwf("bad lazy bind opcode %d", *p
);
1192 template <typename A
>
1193 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1195 if ( fInfo
== NULL
) {
1196 printf("no compressed dyld info\n");
1198 else if ( fInfo
->lazy_bind_off() == 0 ) {
1199 printf("no compressed lazy binding info\n");
1202 printf("lazy binding opcodes:\n");
1203 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1204 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1205 uint8_t type
= BIND_TYPE_POINTER
;
1207 uint64_t address
= fBaseAddress
;
1208 const char* symbolName
= NULL
;
1209 int libraryOrdinal
= 0;
1211 uint32_t segmentIndex
= 0;
1214 for (const uint8_t* p
= start
; p
< end
; ) {
1215 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1216 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1217 uint32_t opcodeOffset
= p
-start
;
1220 case BIND_OPCODE_DONE
:
1221 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1223 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1224 libraryOrdinal
= immediate
;
1225 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1227 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1228 libraryOrdinal
= read_uleb128(p
, end
);
1229 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1231 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1232 // the special ordinals are negative numbers
1233 if ( immediate
== 0 )
1236 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1237 libraryOrdinal
= signExtended
;
1239 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1241 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1243 symbolName
= (char*)p
;
1247 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1249 case BIND_OPCODE_SET_TYPE_IMM
:
1251 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1253 case BIND_OPCODE_SET_ADDEND_SLEB
:
1254 addend
= read_sleb128(p
, end
);
1255 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1257 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1258 segmentIndex
= immediate
;
1259 address
= read_uleb128(p
, end
);
1260 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1262 case BIND_OPCODE_ADD_ADDR_ULEB
:
1263 skip
= read_uleb128(p
, end
);
1264 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1266 case BIND_OPCODE_DO_BIND
:
1267 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1269 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1270 skip
= read_uleb128(p
, end
);
1271 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1273 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1274 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1275 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1277 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1278 count
= read_uleb128(p
, end
);
1279 skip
= read_uleb128(p
, end
);
1280 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1283 throwf("unknown bind opcode %d", *p
);
1290 struct SortExportsByAddress
1292 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1294 return ( left
.address
< right
.address
);
1298 template <typename A
>
1299 void DyldInfoPrinter
<A
>::printExportInfo()
1301 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1302 printf("no compressed export info\n");
1305 printf("export information (from trie):\n");
1306 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1307 const uint8_t* end
= &start
[fInfo
->export_size()];
1308 std::vector
<mach_o::trie::Entry
> list
;
1309 parseTrie(start
, end
, list
);
1310 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1311 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1312 const bool reExport
= (it
->flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
);
1313 const bool weakDef
= (it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
);
1314 const bool threadLocal
= ((it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
);
1315 const bool abs
= ((it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
);
1316 const bool resolver
= (it
->flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
);
1318 printf("[re-export] ");
1320 printf("0x%08llX ", fBaseAddress
+it
->address
);
1321 printf("%s", it
->name
);
1322 if ( weakDef
|| threadLocal
|| resolver
|| abs
) {
1323 bool needComma
= false;
1329 if ( threadLocal
) {
1332 printf("per-thread");
1344 printf("resolver=0x%08llX", it
->other
);
1350 if ( it
->importName
[0] == '\0' )
1351 printf(" (from %s)", fDylibs
[it
->other
- 1]);
1353 printf(" (%s from %s)", it
->importName
, fDylibs
[it
->other
- 1]);
1361 template <typename A
>
1362 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1363 const uint8_t* parent
, const uint8_t* p
,
1364 char* cummulativeString
, int curStrOffset
)
1366 const uint8_t* const me
= p
;
1367 const uint64_t terminalSize
= read_uleb128(p
, end
);
1368 const uint8_t* children
= p
+ terminalSize
;
1369 if ( terminalSize
!= 0 ) {
1370 uint32_t flags
= read_uleb128(p
, end
);
1371 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1372 uint64_t ordinal
= read_uleb128(p
, end
);
1373 const char* importName
= (const char*)p
;
1377 if ( *importName
== '\0' )
1378 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, ordinal
);
1380 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, importName
, ordinal
);
1383 uint64_t address
= read_uleb128(p
, end
);
1384 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1385 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
1386 read_uleb128(p
, end
);
1390 printf("\tnode%03ld;\n", (long)(me
-start
));
1392 const uint8_t childrenCount
= *children
++;
1393 const uint8_t* s
= children
;
1394 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1395 const char* edgeName
= (char*)s
;
1397 while (*s
!= '\0') {
1398 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1401 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1402 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1403 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1404 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1408 template <typename A
>
1409 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1411 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1412 printf("no compressed export info\n");
1415 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1416 const uint8_t* end
= &p
[fInfo
->export_size()];
1417 char cummulativeString
[2000];
1418 printf("digraph {\n");
1419 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1424 template <typename A
>
1425 void DyldInfoPrinter
<A
>::gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
1426 const uint8_t* parent
, const uint8_t* p
,
1427 std::vector
<uint32_t>& nodeStarts
)
1429 nodeStarts
.push_back(p
-start
);
1430 const uint8_t terminalSize
= read_uleb128(p
, end
);
1431 const uint8_t* children
= p
+ terminalSize
;
1433 const uint8_t childrenCount
= *children
++;
1434 const uint8_t* s
= children
;
1435 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1436 // skip over edge string
1440 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1441 gatherNodeStarts(start
, end
, start
, start
+childNodeOffet
, nodeStarts
);
1446 template <typename A
>
1447 void DyldInfoPrinter
<A
>::printExportInfoNodes()
1449 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1450 printf("no compressed export info\n");
1453 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1454 const uint8_t* end
= &start
[fInfo
->export_size()];
1455 std::vector
<uint32_t> nodeStarts
;
1456 gatherNodeStarts(start
, end
, start
, start
, nodeStarts
);
1457 std::sort(nodeStarts
.begin(), nodeStarts
.end());
1458 for (std::vector
<uint32_t>::const_iterator it
=nodeStarts
.begin(); it
!= nodeStarts
.end(); ++it
) {
1459 printf("0x%04X: ", *it
);
1460 const uint8_t* p
= start
+ *it
;
1461 uint64_t exportInfoSize
= read_uleb128(p
, end
);
1462 if ( exportInfoSize
!= 0 ) {
1463 // print terminal info
1464 uint64_t flags
= read_uleb128(p
, end
);
1465 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1466 uint64_t ordinal
= read_uleb128(p
, end
);
1467 const char* importName
= (const char*)p
;
1471 if ( strlen(importName
) == 0 )
1472 printf("[flags=REEXPORT ordinal=%llu] ", ordinal
);
1474 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal
, importName
);
1476 else if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1477 uint64_t stub
= read_uleb128(p
, end
);
1478 uint64_t resolver
= read_uleb128(p
, end
);
1479 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub
, resolver
);
1482 uint64_t address
= read_uleb128(p
, end
);
1483 if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR
)
1484 printf("[addr=0x%06llX] ", address
);
1485 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1486 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address
);
1487 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
)
1488 printf("[flags=ABSOLUTE addr=0x%06llX] ", address
);
1490 printf("[flags=0x%llX addr=0x%06llX] ", flags
, address
);
1493 // print child edges
1494 const uint8_t childrenCount
= *p
++;
1495 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1496 const char* edgeName
= (const char*)p
;
1500 uint32_t childNodeOffet
= read_uleb128(p
, end
);
1501 printf("%s->0x%04X", edgeName
, childNodeOffet
);
1502 if ( i
< (childrenCount
-1) )
1512 template <typename A
>
1513 const uint8_t* DyldInfoPrinter
<A
>::printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p
, const uint8_t* end
, uint8_t kind
)
1515 const char* kindStr
= "??";
1517 case DYLD_CACHE_ADJ_V1_POINTER_32
:
1518 kindStr
= "32-bit pointer";
1520 case DYLD_CACHE_ADJ_V1_POINTER_64
:
1521 kindStr
= "64-bit pointer";
1523 case DYLD_CACHE_ADJ_V1_ADRP
:
1524 kindStr
= "arm64 ADRP";
1526 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+0:
1527 kindStr
= "thumb2 movt low high 4 bits=0";
1529 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+1:
1530 kindStr
= "thumb2 movt low high 4 bits=1";
1532 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+2:
1533 kindStr
= "thumb2 movt low high 4 bits=2";
1535 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+3:
1536 kindStr
= "thumb2 movt low high 4 bits=3";
1538 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+4:
1539 kindStr
= "thumb2 movt low high 4 bits=4";
1541 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+5:
1542 kindStr
= "thumb2 movt low high 4 bits=5";
1544 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+6:
1545 kindStr
= "thumb2 movt low high 4 bits=6";
1547 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+7:
1548 kindStr
= "thumb2 movt low high 4 bits=7";
1550 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+8:
1551 kindStr
= "thumb2 movt low high 4 bits=8";
1553 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+9:
1554 kindStr
= "thumb2 movt low high 4 bits=9";
1556 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+10:
1557 kindStr
= "thumb2 movt low high 4 bits=10";
1559 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+11:
1560 kindStr
= "thumb2 movt low high 4 bits=11";
1562 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+12:
1563 kindStr
= "thumb2 movt low high 4 bits=12";
1565 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+13:
1566 kindStr
= "thumb2 movt low high 4 bits=13";
1568 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+14:
1569 kindStr
= "thumb2 movt low high 4 bits=14";
1571 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+15:
1572 kindStr
= "thumb2 movt low high 4 bits=15";
1574 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+0:
1575 kindStr
= "arm movt low high 4 bits=0";
1577 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+1:
1578 kindStr
= "arm movt low high 4 bits=1";
1580 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+2:
1581 kindStr
= "arm movt low high 4 bits=2";
1583 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+3:
1584 kindStr
= "arm movt low high 4 bits=3";
1586 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+4:
1587 kindStr
= "arm movt low high 4 bits=4";
1589 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+5:
1590 kindStr
= "arm movt low high 4 bits=5";
1592 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+6:
1593 kindStr
= "arm movt low high 4 bits=6";
1595 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+7:
1596 kindStr
= "arm movt low high 4 bits=7";
1598 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+8:
1599 kindStr
= "arm movt low high 4 bits=8";
1601 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+9:
1602 kindStr
= "arm movt low high 4 bits=9";
1604 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+10:
1605 kindStr
= "arm movt low high 4 bits=10";
1607 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+11:
1608 kindStr
= "arm movt low high 4 bits=11";
1610 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+12:
1611 kindStr
= "arm movt low high 4 bits=12";
1613 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+13:
1614 kindStr
= "arm movt low high 4 bits=13";
1616 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+14:
1617 kindStr
= "arm movt low high 4 bits=14";
1619 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+15:
1620 kindStr
= "arm movt low high 4 bits=15";
1623 kindStr
= "<<unknown>>";
1625 uint64_t address
= 0;
1628 delta
= read_uleb128(p
, end
);
1630 printf("0x%0llX %s\n", address
+fBaseAddress
, kindStr
);
1636 template <typename A
>
1637 void DyldInfoPrinter
<A
>::printSharedRegionInfo()
1639 if ( (fSharedRegionInfo
== NULL
) || (fSharedRegionInfo
->datasize() == 0) ) {
1640 printf("no shared region info\n");
1643 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fSharedRegionInfo
->dataoff();
1644 const uint8_t* infoEnd
= &infoStart
[fSharedRegionInfo
->datasize()];
1645 if ( *infoStart
== DYLD_CACHE_ADJ_V2_FORMAT
) {
1647 // Whole :== <count> FromToSection+
1648 // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
1649 // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
1650 // FromOffset :== <kind> <count> <from-sect-offset-delta>
1651 const uint8_t* p
= infoStart
;
1652 uint64_t sectionCount
= read_uleb128(p
, infoEnd
);
1653 for (uint64_t i
=0; i
< sectionCount
; ++i
) {
1654 uint64_t fromSectionIndex
= read_uleb128(p
, infoEnd
);
1655 uint64_t toSectionIndex
= read_uleb128(p
, infoEnd
);
1656 uint64_t toOffsetCount
= read_uleb128(p
, infoEnd
);
1657 const macho_section
<P
>* fromSection
= fSections
[fromSectionIndex
];
1658 const macho_section
<P
>* toSection
= fSections
[toSectionIndex
];
1659 char fromSectionName
[20];
1660 strncpy(fromSectionName
, fromSection
->sectname(), 16);
1661 fromSectionName
[16] = '\0';
1662 printf("from sect=%s/%s, to sect=%s/%s, count=%lld:\n", fromSection
->segname(), fromSectionName
, toSection
->segname(), toSection
->sectname(), toOffsetCount
);
1663 uint64_t toSectionOffset
= 0;
1664 const char* lastFromSymbol
= NULL
;
1665 for (uint64_t j
=0; j
< toOffsetCount
; ++j
) {
1666 uint64_t toSectionDelta
= read_uleb128(p
, infoEnd
);
1667 uint64_t fromOffsetCount
= read_uleb128(p
, infoEnd
);
1668 toSectionOffset
+= toSectionDelta
;
1669 for (uint64_t k
=0; k
< fromOffsetCount
; ++k
) {
1670 uint64_t kind
= read_uleb128(p
, infoEnd
);
1671 uint64_t fromSectDeltaCount
= read_uleb128(p
, infoEnd
);
1672 uint64_t fromSectionOffset
= 0;
1673 for (uint64_t l
=0; l
< fromSectDeltaCount
; ++l
) {
1674 uint64_t delta
= read_uleb128(p
, infoEnd
);
1675 fromSectionOffset
+= delta
;
1676 uint64_t symbolOffset
;
1677 const char* s
= closestSymbolNameForAddress(fromSection
->addr()+fromSectionOffset
, &symbolOffset
, fromSectionIndex
);
1678 if ( (s
!= lastFromSymbol
) && (s
!= NULL
) )
1679 printf(" %s:\n", s
);
1680 const char* toSymbol
= closestSymbolNameForAddress(toSection
->addr()+toSectionOffset
, &symbolOffset
, toSectionIndex
);
1681 printf(" from addr=0x%0llX %s to addr=0x%0llX", fromSection
->addr()+fromSectionOffset
, sharedRegionKindName(kind
), toSection
->addr()+toSectionOffset
);
1682 if ( toSymbol
!= NULL
) {
1683 if ( symbolOffset
== 0 )
1684 printf(" (%s)", toSymbol
);
1686 printf(" (%s + %lld)", toSymbol
, symbolOffset
);
1696 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
);) {
1697 uint8_t kind
= *p
++;
1698 p
= this->printSharedRegionV1InfoForEachULEB128Address(p
, infoEnd
, kind
);
1704 template <typename A
>
1705 const char* DyldInfoPrinter
<A
>::sharedRegionKindName(uint8_t kind
)
1709 return "<<unknown>>";
1710 case DYLD_CACHE_ADJ_V2_POINTER_32
:
1712 case DYLD_CACHE_ADJ_V2_POINTER_64
:
1714 case DYLD_CACHE_ADJ_V2_DELTA_32
:
1716 case DYLD_CACHE_ADJ_V2_DELTA_64
:
1718 case DYLD_CACHE_ADJ_V2_ARM64_ADRP
:
1720 case DYLD_CACHE_ADJ_V2_ARM64_OFF12
:
1722 case DYLD_CACHE_ADJ_V2_ARM64_BR26
:
1724 case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT
:
1726 case DYLD_CACHE_ADJ_V2_ARM_BR24
:
1728 case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT
:
1730 case DYLD_CACHE_ADJ_V2_THUMB_BR22
:
1732 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32
:
1738 #if SUPPORT_ARCH_arm_any
1740 void DyldInfoPrinter
<arm
>::printFunctionStartLine(uint64_t addr
)
1743 printf("0x%0llX [thumb] %s\n", (addr
& -2), symbolNameForAddress(addr
& -2));
1745 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1749 template <typename A
>
1750 void DyldInfoPrinter
<A
>::printFunctionStartLine(uint64_t addr
)
1752 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1756 template <typename A
>
1757 void DyldInfoPrinter
<A
>::printFunctionStartsInfo()
1759 if ( (fFunctionStartsInfo
== NULL
) || (fFunctionStartsInfo
->datasize() == 0) ) {
1760 printf("no function starts info\n");
1763 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fFunctionStartsInfo
->dataoff();
1764 const uint8_t* infoEnd
= &infoStart
[fFunctionStartsInfo
->datasize()];
1765 uint64_t address
= fBaseAddress
;
1766 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
); ) {
1771 uint8_t byte
= *p
++;
1772 delta
|= ((byte
& 0x7F) << shift
);
1774 if ( byte
< 0x80 ) {
1776 printFunctionStartLine(address
);
1784 template <typename A
>
1785 void DyldInfoPrinter
<A
>::printDylibsInfo()
1787 printf("attributes dependent dylibs\n");
1788 for(typename
std::vector
<const macho_dylib_command
<P
>*>::iterator it
= fDylibLoadCommands
.begin(); it
!= fDylibLoadCommands
.end(); ++it
) {
1789 const macho_dylib_command
<P
>* dylib
= *it
;
1790 const char* attribute
= "";
1791 switch ( dylib
->cmd() ) {
1792 case LC_LOAD_WEAK_DYLIB
:
1793 attribute
= "weak_import";
1795 case LC_REEXPORT_DYLIB
:
1796 attribute
= "re-export";
1798 case LC_LOAD_UPWARD_DYLIB
:
1799 attribute
= "upward";
1801 case LC_LAZY_LOAD_DYLIB
:
1802 attribute
= "lazy_load";
1808 printf(" %-12s %s\n", attribute
, dylib
->name());
1812 template <typename A
>
1813 void DyldInfoPrinter
<A
>::printDRInfo()
1815 if ( fDRInfo
== NULL
) {
1816 printf("no Designated Requirements info\n");
1819 printf("dylibs DRs\n");
1820 const uint8_t* start
= ((uint8_t*)fHeader
+ fDRInfo
->dataoff());
1821 //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
1822 typedef Security::SuperBlob
<Security::kSecCodeMagicDRList
> DRListSuperBlob
;
1823 const DRListSuperBlob
* topBlob
= (DRListSuperBlob
*)start
;
1824 if ( topBlob
->validateBlob(fDRInfo
->datasize()) ) {
1825 if ( topBlob
->count() == fDylibLoadCommands
.size() ) {
1826 for(unsigned i
=0; i
< topBlob
->count(); ++i
) {
1827 printf(" %-20s ", fDylibs
[i
]);
1828 const Security::BlobCore
* item
= topBlob
->find(i
);
1829 if ( item
!= NULL
) {
1830 const uint8_t* itemStart
= (uint8_t*)item
;
1831 const uint8_t* itemEnd
= itemStart
+ item
->length();
1832 for(const uint8_t* p
=itemStart
; p
< itemEnd
; ++p
)
1833 printf("%02X ", *p
);
1836 printf("no DR info");
1842 fprintf(stderr
, "superblob of DRs has a different number of elements than dylib load commands\n");
1846 fprintf(stderr
, "superblob of DRs invalid\n");
1855 template <typename A
>
1856 void DyldInfoPrinter
<A
>::printDataInCode()
1858 if ( fDataInCode
== NULL
) {
1859 printf("no data-in-code info\n");
1862 printf("offset length data-kind\n");
1863 const macho_data_in_code_entry
<P
>* start
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff());
1864 const macho_data_in_code_entry
<P
>* end
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff() + fDataInCode
->datasize());
1865 for (const macho_data_in_code_entry
<P
>* p
=start
; p
< end
; ++p
) {
1866 const char* kindStr
= "???";
1867 switch ( p
->kind() ) {
1872 kindStr
= "jumptable8";
1875 kindStr
= "jumptable16";
1878 kindStr
= "jumptable32";
1881 kindStr
= "jumptable32absolute";
1884 printf("0x%08X 0x%04X %s\n", p
->offset(), p
->length(), kindStr
);
1892 ppc::P::uint_t DyldInfoPrinter
<ppc
>::relocBase()
1894 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1895 return fFirstWritableSegment
->vmaddr();
1897 return fFirstSegment
->vmaddr();
1901 ppc64::P::uint_t DyldInfoPrinter
<ppc64
>::relocBase()
1903 if ( fWriteableSegmentWithAddrOver4G
)
1904 return fFirstWritableSegment
->vmaddr();
1906 return fFirstSegment
->vmaddr();
1910 x86::P::uint_t DyldInfoPrinter
<x86
>::relocBase()
1912 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1913 return fFirstWritableSegment
->vmaddr();
1915 return fFirstSegment
->vmaddr();
1919 x86_64::P::uint_t DyldInfoPrinter
<x86_64
>::relocBase()
1921 return fFirstWritableSegment
->vmaddr();
1924 #if SUPPORT_ARCH_arm_any
1926 arm::P::uint_t DyldInfoPrinter
<arm
>::relocBase()
1928 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1929 return fFirstWritableSegment
->vmaddr();
1931 return fFirstSegment
->vmaddr();
1935 #if SUPPORT_ARCH_arm64
1937 arm64::P::uint_t DyldInfoPrinter
<arm64
>::relocBase()
1939 return fFirstWritableSegment
->vmaddr();
1945 const char* DyldInfoPrinter
<ppc
>::relocTypeName(uint8_t r_type
)
1947 if ( r_type
== GENERIC_RELOC_VANILLA
)
1954 const char* DyldInfoPrinter
<ppc64
>::relocTypeName(uint8_t r_type
)
1956 if ( r_type
== GENERIC_RELOC_VANILLA
)
1963 const char* DyldInfoPrinter
<x86
>::relocTypeName(uint8_t r_type
)
1965 if ( r_type
== GENERIC_RELOC_VANILLA
)
1967 else if ( r_type
== GENERIC_RELOC_PB_LA_PTR
)
1968 return "pb pointer";
1974 const char* DyldInfoPrinter
<x86_64
>::relocTypeName(uint8_t r_type
)
1976 if ( r_type
== X86_64_RELOC_UNSIGNED
)
1982 #if SUPPORT_ARCH_arm_any
1984 const char* DyldInfoPrinter
<arm
>::relocTypeName(uint8_t r_type
)
1986 if ( r_type
== ARM_RELOC_VANILLA
)
1988 else if ( r_type
== ARM_RELOC_PB_LA_PTR
)
1989 return "pb pointer";
1995 #if SUPPORT_ARCH_arm64
1997 const char* DyldInfoPrinter
<arm64
>::relocTypeName(uint8_t r_type
)
1999 if ( r_type
== ARM64_RELOC_UNSIGNED
)
2006 template <typename A
>
2007 void DyldInfoPrinter
<A
>::printRelocRebaseInfo()
2009 if ( fDynamicSymbolTable
== NULL
) {
2010 printf("no classic dynamic symbol table");
2013 printf("rebase information (from local relocation records and indirect symbol table):\n");
2014 printf("segment section address type\n");
2015 // walk all local relocations
2016 pint_t rbase
= relocBase();
2017 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->locreloff());
2018 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nlocrel()];
2019 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2020 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
2021 pint_t addr
= reloc
->r_address() + rbase
;
2022 uint8_t segIndex
= segmentIndexForAddress(addr
);
2023 const char* typeName
= relocTypeName(reloc
->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 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
2030 pint_t addr
= sreloc
->r_address() + rbase
;
2031 uint8_t segIndex
= segmentIndexForAddress(addr
);
2032 const char* typeName
= relocTypeName(sreloc
->r_type());
2033 const char* segName
= segmentName(segIndex
);
2034 const char* sectName
= sectionName(segIndex
, addr
);
2035 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
2038 // look for local non-lazy-pointers
2039 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2040 uint8_t segIndex
= 0;
2041 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
, ++segIndex
) {
2042 const macho_segment_command
<P
>* segCmd
= *segit
;
2043 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2044 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2045 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2046 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2047 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2048 uint32_t indirectOffset
= sect
->reserved1();
2049 uint32_t count
= sect
->size() / sizeof(pint_t
);
2050 for (uint32_t i
=0; i
< count
; ++i
) {
2051 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2052 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
2053 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2054 const char* typeName
= "pointer";
2055 const char* segName
= segmentName(segIndex
);
2056 const char* sectName
= sectionName(segIndex
, addr
);
2057 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
2067 template <typename A
>
2068 void DyldInfoPrinter
<A
>::printSymbolTableExportInfo()
2070 if ( fDynamicSymbolTable
== NULL
) {
2071 printf("no classic dynamic symbol table");
2074 printf("export information (from symbol table):\n");
2075 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
2076 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
2077 const char* flags
= "";
2078 if ( sym
->n_desc() & N_WEAK_DEF
)
2079 flags
= "[weak_def] ";
2081 if ( sym
->n_desc() & N_ARM_THUMB_DEF
)
2083 printf("0x%08llX %s%s\n", sym
->n_value()+thumb
, flags
, &fStrings
[sym
->n_strx()]);
2088 template <typename A
>
2089 const char* DyldInfoPrinter
<A
>::closestSymbolNameForAddress(uint64_t addr
, uint64_t* offset
, uint8_t sectIndex
)
2091 const macho_nlist
<P
>* bestSymbol
= NULL
;
2092 if ( fDynamicSymbolTable
!= NULL
) {
2093 // find closest match in globals
2094 const macho_nlist
<P
>* const globalsStart
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()];
2095 const macho_nlist
<P
>* const globalsEnd
= &globalsStart
[fDynamicSymbolTable
->nextdefsym()];
2096 for (const macho_nlist
<P
>* s
= globalsStart
; s
< globalsEnd
; ++s
) {
2097 if ( (s
->n_type() & N_TYPE
) == N_SECT
) {
2098 if ( (s
->n_value() <= addr
) && ((s
->n_sect() == sectIndex
) || (sectIndex
==0)) ) {
2099 if ( (bestSymbol
== NULL
) || (bestSymbol
->n_value() < s
->n_value()) )
2105 // find closest match in locals
2106 const macho_nlist
<P
>* const localsStart
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()];
2107 const macho_nlist
<P
>* const localsEnd
= &localsStart
[fDynamicSymbolTable
->nlocalsym()];
2108 for (const macho_nlist
<P
>* s
= localsStart
; s
< localsEnd
; ++s
) {
2109 if ( ((s
->n_type() & N_TYPE
) == N_SECT
) && ((s
->n_type() & N_STAB
) == 0) ) {
2110 if ( (s
->n_value() <= addr
) && ((s
->n_sect() == sectIndex
) || (sectIndex
==0)) ) {
2111 if ( (bestSymbol
== NULL
) || (bestSymbol
->n_value() < s
->n_value()) )
2118 // find closest match in locals
2119 const macho_nlist
<P
>* const allStart
= &fSymbols
[0];
2120 const macho_nlist
<P
>* const allEnd
= &fSymbols
[fSymbolCount
];
2121 for (const macho_nlist
<P
>* s
= allStart
; s
< allEnd
; ++s
) {
2122 if ( ((s
->n_type() & N_TYPE
) == N_SECT
) && ((s
->n_type() & N_STAB
) == 0) ) {
2123 if ( (s
->n_value() <= addr
) && ((s
->n_sect() == sectIndex
) || (sectIndex
==0)) ) {
2124 if ( (bestSymbol
== NULL
) || (bestSymbol
->n_value() < s
->n_value()) )
2130 if ( bestSymbol
!= NULL
) {
2131 *offset
= addr
- bestSymbol
->n_value();
2132 return &fStrings
[bestSymbol
->n_strx()];
2138 template <typename A
>
2139 const char* DyldInfoPrinter
<A
>::symbolNameForAddress(uint64_t addr
)
2142 const char* s
= closestSymbolNameForAddress(addr
, &offset
);
2143 if ( (offset
== 0) && (s
!= NULL
) )
2148 template <typename A
>
2149 void DyldInfoPrinter
<A
>::printClassicBindingInfo()
2151 if ( fDynamicSymbolTable
== NULL
) {
2152 printf("no classic dynamic symbol table");
2155 printf("binding information (from relocations and indirect symbol table):\n");
2156 printf("segment section address type weak addend dylib symbol\n");
2157 // walk all external relocations
2158 pint_t rbase
= relocBase();
2159 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->extreloff());
2160 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
2161 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2162 pint_t addr
= reloc
->r_address() + rbase
;
2163 uint32_t symbolIndex
= reloc
->r_symbolnum();
2164 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2165 const char* symbolName
= &fStrings
[sym
->n_strx()];
2166 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
2167 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2168 uint8_t segIndex
= segmentIndexForAddress(addr
);
2169 const char* typeName
= relocTypeName(reloc
->r_type());
2170 const char* segName
= segmentName(segIndex
);
2171 const char* sectName
= sectionName(segIndex
, addr
);
2172 const pint_t
* addressMapped
= mappedAddressForVMAddress(addr
);
2173 int64_t addend
= P::getP(*addressMapped
);
2174 if ( fHeader
->flags() & MH_PREBOUND
) {
2175 // In prebound binaries the content is already pointing to the target.
2176 // To get the addend requires subtracting out the base address it was prebound to.
2177 addend
-= sym
->n_value();
2179 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
2180 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
2182 // look for non-lazy pointers
2183 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2184 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2185 const macho_segment_command
<P
>* segCmd
= *segit
;
2186 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2187 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2188 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2189 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2190 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2191 uint32_t indirectOffset
= sect
->reserved1();
2192 uint32_t count
= sect
->size() / sizeof(pint_t
);
2193 for (uint32_t i
=0; i
< count
; ++i
) {
2194 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2195 if ( symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
2196 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2197 const char* symbolName
= &fStrings
[sym
->n_strx()];
2198 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
2199 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2200 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2201 uint8_t segIndex
= segmentIndexForAddress(addr
);
2202 const char* typeName
= "pointer";
2203 const char* segName
= segmentName(segIndex
);
2204 const char* sectName
= sectionName(segIndex
, addr
);
2206 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
2207 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
2217 template <typename A
>
2218 void DyldInfoPrinter
<A
>::printClassicLazyBindingInfo()
2220 if ( fDynamicSymbolTable
== NULL
) {
2221 printf("no classic dynamic symbol table");
2224 printf("lazy binding information (from section records and indirect symbol table):\n");
2225 printf("segment section address index dylib symbol\n");
2226 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2227 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2228 const macho_segment_command
<P
>* segCmd
= *segit
;
2229 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2230 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2231 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2232 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2233 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2234 uint32_t indirectOffset
= sect
->reserved1();
2235 uint32_t count
= sect
->size() / sizeof(pint_t
);
2236 for (uint32_t i
=0; i
< count
; ++i
) {
2237 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2238 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2239 const char* symbolName
= &fStrings
[sym
->n_strx()];
2240 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2241 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2242 uint8_t segIndex
= segmentIndexForAddress(addr
);
2243 const char* segName
= segmentName(segIndex
);
2244 const char* sectName
= sectionName(segIndex
, addr
);
2245 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2248 else if ( (type
== S_SYMBOL_STUBS
) && (((sect
->flags() & S_ATTR_SELF_MODIFYING_CODE
) != 0)) && (sect
->reserved2() == 5) ) {
2249 // i386 self-modifying stubs
2250 uint32_t indirectOffset
= sect
->reserved1();
2251 uint32_t count
= sect
->size() / 5;
2252 for (uint32_t i
=0; i
< count
; ++i
) {
2253 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2254 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
2255 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2256 const char* symbolName
= &fStrings
[sym
->n_strx()];
2257 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2258 pint_t addr
= sect
->addr() + i
*5;
2259 uint8_t segIndex
= segmentIndexForAddress(addr
);
2260 const char* segName
= segmentName(segIndex
);
2261 const char* sectName
= sectionName(segIndex
, addr
);
2262 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2271 static void dump(const char* path
)
2273 struct stat stat_buf
;
2276 int fd
= ::open(path
, O_RDONLY
, 0);
2278 throw "cannot open file";
2279 if ( ::fstat(fd
, &stat_buf
) != 0 )
2280 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
2281 uint32_t length
= stat_buf
.st_size
;
2282 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
2283 if ( p
== ((uint8_t*)(-1)) )
2284 throw "cannot map file";
2286 const mach_header
* mh
= (mach_header
*)p
;
2287 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2288 const struct fat_header
* fh
= (struct fat_header
*)p
;
2289 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
2290 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2291 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2292 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
2293 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
2294 cpu_type_t cpusubtype
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
);
2295 if ( ((cputype
== sPreferredArch
)
2296 && ((sPreferredSubArch
==0) || (sPreferredSubArch
==cpusubtype
)))
2297 || (sPreferredArch
== 0) ) {
2299 case CPU_TYPE_POWERPC
:
2300 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
2301 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2303 throw "in universal file, ppc slice does not contain ppc mach-o";
2306 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
2307 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2309 throw "in universal file, i386 slice does not contain i386 mach-o";
2311 case CPU_TYPE_POWERPC64
:
2312 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
2313 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2315 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
2317 case CPU_TYPE_X86_64
:
2318 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
2319 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2321 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
2323 #if SUPPORT_ARCH_arm_any
2325 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
2326 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2328 throw "in universal file, arm slice does not contain arm mach-o";
2331 #if SUPPORT_ARCH_arm64
2332 case CPU_TYPE_ARM64
:
2333 if ( DyldInfoPrinter
<arm64
>::validFile(p
+ offset
) )
2334 DyldInfoPrinter
<arm64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2336 throw "in universal file, arm64 slice does not contain arm64 mach-o";
2340 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
2345 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
2346 DyldInfoPrinter
<x86
>::make(p
, length
, path
, false);
2348 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
2349 DyldInfoPrinter
<ppc
>::make(p
, length
, path
, false);
2351 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
2352 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
, false);
2354 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
2355 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
, false);
2357 #if SUPPORT_ARCH_arm_any
2358 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
2359 DyldInfoPrinter
<arm
>::make(p
, length
, path
, false);
2362 #if SUPPORT_ARCH_arm64
2363 else if ( DyldInfoPrinter
<arm64
>::validFile(p
) ) {
2364 DyldInfoPrinter
<arm64
>::make(p
, length
, path
, false);
2368 throw "not a known file type";
2371 catch (const char* msg
) {
2372 throwf("%s in %s", msg
, path
);
2378 fprintf(stdout
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
2379 "\t-dylibs print dependent dylibs\n"
2380 "\t-dr print dependent dylibs and show any recorded DR info\n"
2381 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
2382 "\t-bind print addresses dyld will set based on symbolic lookups\n"
2383 "\t-weak_bind print symbols which dyld must coalesce\n"
2384 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
2385 "\t-export print addresses of all symbols this file exports\n"
2386 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
2387 "\t-function_starts print table of function start addresses\n"
2388 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
2389 "\t-data_in_code print any data-in-code information\n"
2394 int main(int argc
, const char* argv
[])
2402 std::vector
<const char*> files
;
2403 for(int i
=1; i
< argc
; ++i
) {
2404 const char* arg
= argv
[i
];
2405 if ( arg
[0] == '-' ) {
2406 if(strcmp(arg
, "--version") == 0){
2407 /* Implement a gnu-style --version. */
2408 fprintf(stdout
, "xtools-%s dyldinfo %s\nBased on Apple Inc. ld64-%s\n",
2409 XTOOLS_VERSION
, PACKAGE_VERSION
, LD64_VERSION_NUM
);
2411 } else if(strcmp(arg
, "--help") == 0){
2413 #ifdef XTOOLS_BUGURL
2414 fprintf(stdout
, "Please report bugs to %s\n", XTOOLS_BUGURL
);
2418 if ( strcmp(arg
, "-arch") == 0 ) {
2419 const char* arch
= ++i
<argc
? argv
[i
]: "";
2420 if ( strcmp(arch
, "ppc64") == 0 )
2421 sPreferredArch
= CPU_TYPE_POWERPC64
;
2422 else if ( strcmp(arch
, "ppc") == 0 )
2423 sPreferredArch
= CPU_TYPE_POWERPC
;
2424 else if ( strcmp(arch
, "i386") == 0 )
2425 sPreferredArch
= CPU_TYPE_I386
;
2426 else if ( strcmp(arch
, "x86_64") == 0 )
2427 sPreferredArch
= CPU_TYPE_X86_64
;
2428 #if SUPPORT_ARCH_arm64
2429 else if ( strcmp(arch
, "arm64") == 0 )
2430 sPreferredArch
= CPU_TYPE_ARM64
;
2434 throw "-arch missing architecture name";
2436 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
2437 if ( strcmp(t
->archName
,arch
) == 0 ) {
2438 sPreferredArch
= t
->cpuType
;
2440 sPreferredSubArch
= t
->cpuSubType
;
2446 throwf("unknown architecture %s", arch
);
2449 else if ( strcmp(arg
, "-rebase") == 0 ) {
2452 else if ( strcmp(arg
, "-bind") == 0 ) {
2455 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
2456 printWeakBind
= true;
2458 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
2459 printLazyBind
= true;
2461 else if ( strcmp(arg
, "-export") == 0 ) {
2464 else if ( strcmp(arg
, "-opcodes") == 0 ) {
2465 printOpcodes
= true;
2467 else if ( strcmp(arg
, "-export_dot") == 0 ) {
2468 printExportGraph
= true;
2470 else if ( strcmp(arg
, "-export_trie_nodes") == 0 ) {
2471 printExportNodes
= true;
2473 else if ( strcmp(arg
, "-shared_region") == 0 ) {
2474 printSharedRegion
= true;
2476 else if ( strcmp(arg
, "-function_starts") == 0 ) {
2477 printFunctionStarts
= true;
2479 else if ( strcmp(arg
, "-dylibs") == 0 ) {
2482 else if ( strcmp(arg
, "-dr") == 0 ) {
2485 else if ( strcmp(arg
, "-data_in_code") == 0 ) {
2486 printDataCode
= true;
2489 throwf("unknown option: %s\n", arg
);
2493 files
.push_back(arg
);
2496 if ( files
.size() == 0 )
2498 if ( files
.size() == 1 ) {
2502 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
2503 printf("\n%s:\n", *it
);
2508 catch (const char* msg
) {
2509 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);