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()) {
292 template <typename A
>
293 DyldInfoPrinter
<A
>::DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
294 : fHeader(NULL
), fLength(fileLength
),
295 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fInfo(NULL
),
296 fSharedRegionInfo(NULL
), fFunctionStartsInfo(NULL
), fDataInCode(NULL
), fDRInfo(NULL
),
297 fBaseAddress(0), fDynamicSymbolTable(NULL
), fFirstSegment(NULL
), fFirstWritableSegment(NULL
),
298 fWriteableSegmentWithAddrOver4G(false)
301 if ( ! validFile(fileContent
) )
302 throw "not a mach-o file that can be checked";
304 fPath
= strdup(path
);
305 fHeader
= (const macho_header
<P
>*)fileContent
;
307 fMachHeaderPseudoSection
.set_segname("__TEXT");
308 fMachHeaderPseudoSection
.set_sectname("");
309 fMachHeaderPseudoSection
.set_addr(0);
310 fSections
.push_back(&fMachHeaderPseudoSection
);
313 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
314 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
315 const uint32_t cmd_count
= fHeader
->ncmds();
316 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
317 const macho_load_command
<P
>* cmd
= cmds
;
318 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
319 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
320 if ( endOfCmd
> endOfLoadCommands
)
321 throwf("load command #%d extends beyond the end of the load commands", i
);
322 if ( endOfCmd
> endOfFile
)
323 throwf("load command #%d extends beyond the end of the file", i
);
324 switch ( cmd
->cmd() ) {
326 case LC_DYLD_INFO_ONLY
:
327 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
329 case macho_segment_command
<P
>::CMD
:
331 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
332 fSegments
.push_back(segCmd
);
333 if ( (segCmd
->fileoff() == 0) && (segCmd
->filesize() != 0) )
334 fBaseAddress
= segCmd
->vmaddr();
335 if ( fFirstSegment
== NULL
)
336 fFirstSegment
= segCmd
;
337 if ( (segCmd
->initprot() & VM_PROT_WRITE
) != 0 ) {
338 if ( fFirstWritableSegment
== NULL
)
339 fFirstWritableSegment
= segCmd
;
340 if ( segCmd
->vmaddr() > 0x100000000ULL
)
341 fWriteableSegmentWithAddrOver4G
= true;
343 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
344 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
345 for(const macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
)
346 fSections
.push_back(sect
);
350 case LC_LOAD_WEAK_DYLIB
:
351 case LC_REEXPORT_DYLIB
:
352 case LC_LOAD_UPWARD_DYLIB
:
353 case LC_LAZY_LOAD_DYLIB
:
355 const macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
356 fDylibLoadCommands
.push_back(dylib
);
357 const char* lastSlash
= strrchr(dylib
->name(), '/');
358 const char* leafName
= (lastSlash
!= NULL
) ? lastSlash
+1 : dylib
->name();
359 const char* firstDot
= strchr(leafName
, '.');
360 if ( firstDot
!= NULL
) {
361 char* t
= strdup(leafName
);
362 t
[firstDot
-leafName
] = '\0';
363 fDylibs
.push_back(t
);
366 fDylibs
.push_back(leafName
);
371 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
375 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
376 fSymbolCount
= symtab
->nsyms();
377 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
378 fStrings
= (char*)fHeader
+ symtab
->stroff();
379 fStringsEnd
= fStrings
+ symtab
->strsize();
382 case LC_SEGMENT_SPLIT_INFO
:
383 fSharedRegionInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
385 case LC_FUNCTION_STARTS
:
386 fFunctionStartsInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
388 case LC_DATA_IN_CODE
:
389 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
391 case LC_DYLIB_CODE_SIGN_DRS
:
392 fDRInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
395 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
399 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
400 if ( (cpu_type_t
)fHeader
->cputype() == t
->cpuType
) {
401 if ( t
->isSubType
&& ((cpu_subtype_t
)fHeader
->cpusubtype() != t
->cpuSubType
) )
403 printf("for arch %s:\n", t
->archName
);
412 printRelocRebaseInfo();
418 printClassicBindingInfo();
421 printWeakBindingInfo();
422 if ( printLazyBind
) {
424 printLazyBindingInfo();
426 printClassicLazyBindingInfo();
432 printSymbolTableExportInfo();
434 if ( printOpcodes
) {
435 printRebaseInfoOpcodes();
436 printBindingInfoOpcodes(false);
437 printBindingInfoOpcodes(true);
438 printLazyBindingOpcodes();
440 if ( printExportGraph
)
441 printExportInfoGraph();
442 if ( printExportNodes
)
443 printExportInfoNodes();
444 if ( printSharedRegion
)
445 printSharedRegionInfo();
446 if ( printFunctionStarts
)
447 printFunctionStartsInfo();
456 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
462 throwf("malformed uleb128");
464 uint64_t slice
= *p
& 0x7f;
466 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
467 throwf("uleb128 too big");
469 result
|= (slice
<< bit
);
477 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
484 throwf("malformed sleb128");
486 result
|= (((int64_t)(byte
& 0x7f)) << bit
);
488 } while (byte
& 0x80);
489 // sign extend negative numbers
490 if ( (byte
& 0x40) != 0 )
491 result
|= (-1LL) << bit
;
496 template <typename A
>
497 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
500 case REBASE_TYPE_POINTER
:
502 case REBASE_TYPE_TEXT_ABSOLUTE32
:
504 case REBASE_TYPE_TEXT_PCREL32
:
507 return "!!unknown!!";
511 template <typename A
>
512 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
515 case BIND_TYPE_POINTER
:
517 case BIND_TYPE_TEXT_ABSOLUTE32
:
519 case BIND_TYPE_TEXT_PCREL32
:
522 return "!!unknown!!";
526 template <typename A
>
527 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
529 if ( segIndex
> fSegments
.size() )
530 throw "segment index out of range";
531 return fSegments
[segIndex
]->vmaddr();
534 template <typename A
>
535 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
537 if ( segIndex
> fSegments
.size() )
538 throw "segment index out of range";
539 return fSegments
[segIndex
]->segname();
542 template <typename A
>
543 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
545 if ( segIndex
> fSegments
.size() )
546 throw "segment index out of range";
547 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
548 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
549 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
550 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
551 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
552 if ( strlen(sect
->sectname()) > 15 ) {
553 static char temp
[18];
554 strlcpy(temp
, sect
->sectname(), 17);
558 return sect
->sectname();
565 template <typename A
>
566 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
568 static char buffer
[64];
569 strcpy(buffer
, segmentName(segIndex
));
571 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
572 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
573 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
574 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
575 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
576 // section name may not be zero terminated
577 char* end
= &buffer
[strlen(buffer
)];
578 strlcpy(end
, sect
->sectname(), 16);
585 template <typename A
>
586 uint8_t DyldInfoPrinter
<A
>::segmentIndexForAddress(pint_t address
)
588 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
589 if ( (fSegments
[i
]->vmaddr() <= address
) && (address
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
593 throwf("address 0x%llX is not in any segment", (uint64_t)address
);
596 template <typename A
>
597 typename
A::P::uint_t
* DyldInfoPrinter
<A
>::mappedAddressForVMAddress(pint_t vmaddress
)
599 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
600 if ( (fSegments
[i
]->vmaddr() <= vmaddress
) && (vmaddress
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
601 unsigned long offsetInMappedFile
= fSegments
[i
]->fileoff()+vmaddress
-fSegments
[i
]->vmaddr();
602 return (pint_t
*)((uint8_t*)fHeader
+ offsetInMappedFile
);
605 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress
);
608 template <typename A
>
609 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
611 switch ( libraryOrdinal
) {
612 case BIND_SPECIAL_DYLIB_SELF
:
614 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
615 return "main-executable";
616 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
617 return "flat-namespace";
619 if ( libraryOrdinal
< BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
620 throw "unknown special ordinal";
621 if ( libraryOrdinal
> (int)fDylibs
.size() )
622 throw "libraryOrdinal out of range";
623 return fDylibs
[libraryOrdinal
-1];
626 template <typename A
>
627 const char* DyldInfoPrinter
<A
>::classicOrdinalName(int libraryOrdinal
)
629 if ( (fHeader
->flags() & MH_TWOLEVEL
) == 0 )
630 return "flat-namespace";
631 switch ( libraryOrdinal
) {
632 case SELF_LIBRARY_ORDINAL
:
634 case EXECUTABLE_ORDINAL
:
635 return "main-executable";
636 case DYNAMIC_LOOKUP_ORDINAL
:
637 return "flat-namespace";
639 if ( libraryOrdinal
> (int)fDylibs
.size() )
640 throw "libraryOrdinal out of range";
641 return fDylibs
[libraryOrdinal
-1];
644 template <typename A
>
645 void DyldInfoPrinter
<A
>::printRebaseInfo()
647 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
648 printf("no compressed rebase info\n");
651 printf("rebase information (from compressed dyld info):\n");
652 printf("segment section address type\n");
654 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
655 const uint8_t* end
= &p
[fInfo
->rebase_size()];
658 uint64_t segOffset
= 0;
662 pint_t segStartAddr
= 0;
663 const char* segName
= "??";
664 const char* typeName
= "??";
666 while ( !done
&& (p
< end
) ) {
667 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
668 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
671 case REBASE_OPCODE_DONE
:
674 case REBASE_OPCODE_SET_TYPE_IMM
:
676 typeName
= rebaseTypeName(type
);
678 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
679 segIndex
= immediate
;
680 segStartAddr
= segStartAddress(segIndex
);
681 segName
= segmentName(segIndex
);
682 segOffset
= read_uleb128(p
, end
);
684 case REBASE_OPCODE_ADD_ADDR_ULEB
:
685 segOffset
+= read_uleb128(p
, end
);
687 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
688 segOffset
+= immediate
*sizeof(pint_t
);
690 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
691 for (int i
=0; i
< immediate
; ++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_ULEB_TIMES
:
697 count
= read_uleb128(p
, end
);
698 for (uint32_t i
=0; i
< count
; ++i
) {
699 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
700 segOffset
+= sizeof(pint_t
);
703 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
704 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
705 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
707 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
708 count
= read_uleb128(p
, end
);
709 skip
= read_uleb128(p
, end
);
710 for (uint32_t i
=0; i
< count
; ++i
) {
711 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
712 segOffset
+= skip
+ sizeof(pint_t
);
716 throwf("bad rebase opcode %d", *p
);
725 template <typename A
>
726 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
728 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
729 printf("no compressed rebase info\n");
732 printf("rebase opcodes:\n");
733 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
734 const uint8_t* end
= &start
[fInfo
->rebase_size()];
735 const uint8_t* p
= start
;
738 uint64_t address
= fBaseAddress
;
741 unsigned int segmentIndex
;
743 while ( !done
&& (p
< end
) ) {
744 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
745 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
746 uint32_t opcodeOffset
= p
-start
;
749 case REBASE_OPCODE_DONE
:
751 printf("0x%04X REBASE_OPCODE_DONE()\n", opcodeOffset
);
753 case REBASE_OPCODE_SET_TYPE_IMM
:
755 printf("0x%04X REBASE_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
757 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
758 segmentIndex
= immediate
;
759 address
= read_uleb128(p
, end
);
760 printf("0x%04X REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
762 case REBASE_OPCODE_ADD_ADDR_ULEB
:
763 address
= read_uleb128(p
, end
);
764 printf("0x%04X REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", opcodeOffset
, address
);
766 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
767 address
= immediate
*sizeof(pint_t
);
768 printf("0x%04X REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", opcodeOffset
, address
);
770 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
771 printf("0x%04X REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", opcodeOffset
, immediate
);
773 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
774 count
= read_uleb128(p
, end
);
775 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", opcodeOffset
, count
);
777 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
778 skip
= read_uleb128(p
, end
) + sizeof(pint_t
);
779 printf("0x%04X REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", opcodeOffset
, skip
);
781 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
782 count
= read_uleb128(p
, end
);
783 skip
= read_uleb128(p
, end
);
784 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", opcodeOffset
, count
, skip
);
787 throwf("bad rebase opcode %d", *p
);
799 template <typename A
>
800 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
802 if ( fInfo
== NULL
) {
803 printf("no compressed binding info\n");
805 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
806 printf("no compressed binding info\n");
808 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
809 printf("no compressed weak binding info\n");
812 const uint8_t* start
;
815 printf("weak binding opcodes:\n");
816 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
817 end
= &start
[fInfo
->weak_bind_size()];
820 printf("binding opcodes:\n");
821 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
822 end
= &start
[fInfo
->bind_size()];
824 const uint8_t* p
= start
;
827 uint64_t address
= fBaseAddress
;
828 const char* symbolName
= NULL
;
829 int libraryOrdinal
= 0;
831 uint32_t segmentIndex
= 0;
835 while ( !done
&& (p
< end
) ) {
836 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
837 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
838 uint32_t opcodeOffset
= p
-start
;
841 case BIND_OPCODE_DONE
:
843 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
845 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
846 libraryOrdinal
= immediate
;
847 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
849 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
850 libraryOrdinal
= read_uleb128(p
, end
);
851 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
853 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
854 // the special ordinals are negative numbers
855 if ( immediate
== 0 )
858 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
859 libraryOrdinal
= signExtended
;
861 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
863 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
865 symbolName
= (char*)p
;
869 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
871 case BIND_OPCODE_SET_TYPE_IMM
:
873 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
875 case BIND_OPCODE_SET_ADDEND_SLEB
:
876 addend
= read_sleb128(p
, end
);
877 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
879 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
880 segmentIndex
= immediate
;
881 address
= read_uleb128(p
, end
);
882 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
884 case BIND_OPCODE_ADD_ADDR_ULEB
:
885 skip
= read_uleb128(p
, end
);
886 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
888 case BIND_OPCODE_DO_BIND
:
889 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
891 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
892 skip
= read_uleb128(p
, end
);
893 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
895 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
896 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
897 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
899 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
900 count
= read_uleb128(p
, end
);
901 skip
= read_uleb128(p
, end
);
902 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
905 throwf("unknown bind opcode %d", *p
);
914 template <typename A
>
915 void DyldInfoPrinter
<A
>::printBindingInfo()
917 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
918 printf("no compressed binding info\n");
921 printf("bind information:\n");
922 printf("segment section address type addend dylib symbol\n");
923 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->bind_off();
924 const uint8_t* end
= &p
[fInfo
->bind_size()];
927 uint8_t segIndex
= 0;
928 uint64_t segOffset
= 0;
929 const char* symbolName
= NULL
;
930 const char* fromDylib
= "??";
931 int libraryOrdinal
= 0;
935 pint_t segStartAddr
= 0;
936 const char* segName
= "??";
937 const char* typeName
= "??";
938 const char* weak_import
= "";
940 while ( !done
&& (p
< end
) ) {
941 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
942 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
945 case BIND_OPCODE_DONE
:
948 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
949 libraryOrdinal
= immediate
;
950 fromDylib
= ordinalName(libraryOrdinal
);
952 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
953 libraryOrdinal
= read_uleb128(p
, end
);
954 fromDylib
= ordinalName(libraryOrdinal
);
956 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
957 // the special ordinals are negative numbers
958 if ( immediate
== 0 )
961 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
962 libraryOrdinal
= signExtended
;
964 fromDylib
= ordinalName(libraryOrdinal
);
966 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
967 symbolName
= (char*)p
;
971 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
972 weak_import
= " (weak import)";
976 case BIND_OPCODE_SET_TYPE_IMM
:
978 typeName
= bindTypeName(type
);
980 case BIND_OPCODE_SET_ADDEND_SLEB
:
981 addend
= read_sleb128(p
, end
);
983 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
984 segIndex
= immediate
;
985 segStartAddr
= segStartAddress(segIndex
);
986 segName
= segmentName(segIndex
);
987 segOffset
= read_uleb128(p
, end
);
989 case BIND_OPCODE_ADD_ADDR_ULEB
:
990 segOffset
+= read_uleb128(p
, end
);
992 case BIND_OPCODE_DO_BIND
:
993 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
994 segOffset
+= sizeof(pint_t
);
996 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
997 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
998 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1000 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
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
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1004 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1005 count
= read_uleb128(p
, end
);
1006 skip
= read_uleb128(p
, end
);
1007 for (uint32_t i
=0; i
< count
; ++i
) {
1008 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
1009 segOffset
+= skip
+ sizeof(pint_t
);
1013 throwf("bad bind opcode %d", *p
);
1020 template <typename A
>
1021 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
1023 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
1024 printf("no weak binding\n");
1027 printf("weak binding information:\n");
1028 printf("segment section address type addend symbol\n");
1029 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
1030 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
1033 uint8_t segIndex
= 0;
1034 uint64_t segOffset
= 0;
1035 const char* symbolName
= NULL
;
1039 pint_t segStartAddr
= 0;
1040 const char* segName
= "??";
1041 const char* typeName
= "??";
1043 while ( !done
&& (p
< end
) ) {
1044 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1045 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1048 case BIND_OPCODE_DONE
:
1051 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1052 symbolName
= (char*)p
;
1056 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
1057 printf(" strong %s\n", symbolName
);
1059 case BIND_OPCODE_SET_TYPE_IMM
:
1061 typeName
= bindTypeName(type
);
1063 case BIND_OPCODE_SET_ADDEND_SLEB
:
1064 addend
= read_sleb128(p
, end
);
1066 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1067 segIndex
= immediate
;
1068 segStartAddr
= segStartAddress(segIndex
);
1069 segName
= segmentName(segIndex
);
1070 segOffset
= read_uleb128(p
, end
);
1072 case BIND_OPCODE_ADD_ADDR_ULEB
:
1073 segOffset
+= read_uleb128(p
, end
);
1075 case BIND_OPCODE_DO_BIND
:
1076 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1077 segOffset
+= sizeof(pint_t
);
1079 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1080 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1081 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1083 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1084 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1085 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1087 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1088 count
= read_uleb128(p
, end
);
1089 skip
= read_uleb128(p
, end
);
1090 for (uint32_t i
=0; i
< count
; ++i
) {
1091 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1092 segOffset
+= skip
+ sizeof(pint_t
);
1096 throwf("unknown weak bind opcode %d", *p
);
1104 template <typename A
>
1105 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
1107 if ( fInfo
== NULL
) {
1108 printf("no compressed dyld info\n");
1110 else if ( fInfo
->lazy_bind_off() == 0 ) {
1111 printf("no compressed lazy binding info\n");
1114 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1115 printf("segment section address index dylib symbol\n");
1116 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1117 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1119 uint8_t type
= BIND_TYPE_POINTER
;
1120 uint8_t segIndex
= 0;
1121 uint64_t segOffset
= 0;
1122 const char* symbolName
= NULL
;
1123 const char* fromDylib
= "??";
1124 int libraryOrdinal
= 0;
1126 uint32_t lazy_offset
= 0;
1127 pint_t segStartAddr
= 0;
1128 const char* segName
= "??";
1129 const char* typeName
= "??";
1130 const char* weak_import
= "";
1131 for (const uint8_t* p
=start
; p
< end
; ) {
1132 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1133 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1136 case BIND_OPCODE_DONE
:
1137 lazy_offset
= p
-start
;
1139 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1140 libraryOrdinal
= immediate
;
1141 fromDylib
= ordinalName(libraryOrdinal
);
1143 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1144 libraryOrdinal
= read_uleb128(p
, end
);
1145 fromDylib
= ordinalName(libraryOrdinal
);
1147 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1148 // the special ordinals are negative numbers
1149 if ( immediate
== 0 )
1152 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1153 libraryOrdinal
= signExtended
;
1155 fromDylib
= ordinalName(libraryOrdinal
);
1157 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1158 symbolName
= (char*)p
;
1162 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
1163 weak_import
= " (weak import)";
1167 case BIND_OPCODE_SET_TYPE_IMM
:
1169 typeName
= bindTypeName(type
);
1171 case BIND_OPCODE_SET_ADDEND_SLEB
:
1172 addend
= read_sleb128(p
, end
);
1174 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1175 segIndex
= immediate
;
1176 segStartAddr
= segStartAddress(segIndex
);
1177 segName
= segmentName(segIndex
);
1178 segOffset
= read_uleb128(p
, end
);
1180 case BIND_OPCODE_ADD_ADDR_ULEB
:
1181 segOffset
+= read_uleb128(p
, end
);
1183 case BIND_OPCODE_DO_BIND
:
1184 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
, weak_import
);
1185 segOffset
+= sizeof(pint_t
);
1188 throwf("bad lazy bind opcode %d", *p
);
1195 template <typename A
>
1196 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1198 if ( fInfo
== NULL
) {
1199 printf("no compressed dyld info\n");
1201 else if ( fInfo
->lazy_bind_off() == 0 ) {
1202 printf("no compressed lazy binding info\n");
1205 printf("lazy binding opcodes:\n");
1206 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1207 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1208 uint8_t type
= BIND_TYPE_POINTER
;
1210 uint64_t address
= fBaseAddress
;
1211 const char* symbolName
= NULL
;
1212 int libraryOrdinal
= 0;
1214 uint32_t segmentIndex
= 0;
1217 for (const uint8_t* p
= start
; p
< end
; ) {
1218 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1219 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1220 uint32_t opcodeOffset
= p
-start
;
1223 case BIND_OPCODE_DONE
:
1224 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1226 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1227 libraryOrdinal
= immediate
;
1228 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1230 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1231 libraryOrdinal
= read_uleb128(p
, end
);
1232 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1234 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1235 // the special ordinals are negative numbers
1236 if ( immediate
== 0 )
1239 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1240 libraryOrdinal
= signExtended
;
1242 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1244 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1246 symbolName
= (char*)p
;
1250 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1252 case BIND_OPCODE_SET_TYPE_IMM
:
1254 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1256 case BIND_OPCODE_SET_ADDEND_SLEB
:
1257 addend
= read_sleb128(p
, end
);
1258 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1260 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1261 segmentIndex
= immediate
;
1262 address
= read_uleb128(p
, end
);
1263 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1265 case BIND_OPCODE_ADD_ADDR_ULEB
:
1266 skip
= read_uleb128(p
, end
);
1267 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1269 case BIND_OPCODE_DO_BIND
:
1270 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1272 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1273 skip
= read_uleb128(p
, end
);
1274 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1276 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1277 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1278 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1280 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1281 count
= read_uleb128(p
, end
);
1282 skip
= read_uleb128(p
, end
);
1283 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1286 throwf("unknown bind opcode %d", *p
);
1293 struct SortExportsByAddress
1295 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1297 return ( left
.address
< right
.address
);
1301 template <typename A
>
1302 void DyldInfoPrinter
<A
>::printExportInfo()
1304 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1305 printf("no compressed export info\n");
1308 printf("export information (from trie):\n");
1309 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1310 const uint8_t* end
= &start
[fInfo
->export_size()];
1311 std::vector
<mach_o::trie::Entry
> list
;
1312 parseTrie(start
, end
, list
);
1313 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1314 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1315 const bool reExport
= (it
->flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
);
1316 const bool weakDef
= (it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
);
1317 const bool threadLocal
= ((it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
);
1318 const bool abs
= ((it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
);
1319 const bool resolver
= (it
->flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
);
1321 printf("[re-export] ");
1323 printf("0x%08llX ", fBaseAddress
+it
->address
);
1324 printf("%s", it
->name
);
1325 if ( weakDef
|| threadLocal
|| resolver
|| abs
) {
1326 bool needComma
= false;
1332 if ( threadLocal
) {
1335 printf("per-thread");
1347 printf("resolver=0x%08llX", it
->other
);
1353 if ( it
->importName
[0] == '\0' )
1354 printf(" (from %s)", fDylibs
[it
->other
- 1]);
1356 printf(" (%s from %s)", it
->importName
, fDylibs
[it
->other
- 1]);
1364 template <typename A
>
1365 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1366 const uint8_t* parent
, const uint8_t* p
,
1367 char* cummulativeString
, int curStrOffset
)
1369 const uint8_t* const me
= p
;
1370 const uint64_t terminalSize
= read_uleb128(p
, end
);
1371 const uint8_t* children
= p
+ terminalSize
;
1372 if ( terminalSize
!= 0 ) {
1373 uint32_t flags
= read_uleb128(p
, end
);
1374 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1375 uint64_t ordinal
= read_uleb128(p
, end
);
1376 const char* importName
= (const char*)p
;
1380 if ( *importName
== '\0' )
1381 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, ordinal
);
1383 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, importName
, ordinal
);
1386 uint64_t address
= read_uleb128(p
, end
);
1387 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1388 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
1389 read_uleb128(p
, end
);
1393 printf("\tnode%03ld;\n", (long)(me
-start
));
1395 const uint8_t childrenCount
= *children
++;
1396 const uint8_t* s
= children
;
1397 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1398 const char* edgeName
= (char*)s
;
1400 while (*s
!= '\0') {
1401 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1404 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1405 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1406 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1407 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1411 template <typename A
>
1412 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1414 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1415 printf("no compressed export info\n");
1418 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1419 const uint8_t* end
= &p
[fInfo
->export_size()];
1420 char cummulativeString
[2000];
1421 printf("digraph {\n");
1422 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1427 template <typename A
>
1428 void DyldInfoPrinter
<A
>::gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
1429 const uint8_t* parent
, const uint8_t* p
,
1430 std::vector
<uint32_t>& nodeStarts
)
1432 nodeStarts
.push_back(p
-start
);
1433 const uint8_t terminalSize
= read_uleb128(p
, end
);
1434 const uint8_t* children
= p
+ terminalSize
;
1436 const uint8_t childrenCount
= *children
++;
1437 const uint8_t* s
= children
;
1438 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1439 // skip over edge string
1443 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1444 gatherNodeStarts(start
, end
, start
, start
+childNodeOffet
, nodeStarts
);
1449 template <typename A
>
1450 void DyldInfoPrinter
<A
>::printExportInfoNodes()
1452 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1453 printf("no compressed export info\n");
1456 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1457 const uint8_t* end
= &start
[fInfo
->export_size()];
1458 std::vector
<uint32_t> nodeStarts
;
1459 gatherNodeStarts(start
, end
, start
, start
, nodeStarts
);
1460 std::sort(nodeStarts
.begin(), nodeStarts
.end());
1461 for (std::vector
<uint32_t>::const_iterator it
=nodeStarts
.begin(); it
!= nodeStarts
.end(); ++it
) {
1462 printf("0x%04X: ", *it
);
1463 const uint8_t* p
= start
+ *it
;
1464 uint64_t exportInfoSize
= read_uleb128(p
, end
);
1465 if ( exportInfoSize
!= 0 ) {
1466 // print terminal info
1467 uint64_t flags
= read_uleb128(p
, end
);
1468 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1469 uint64_t ordinal
= read_uleb128(p
, end
);
1470 const char* importName
= (const char*)p
;
1474 if ( strlen(importName
) == 0 )
1475 printf("[flags=REEXPORT ordinal=%llu] ", ordinal
);
1477 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal
, importName
);
1479 else if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1480 uint64_t stub
= read_uleb128(p
, end
);
1481 uint64_t resolver
= read_uleb128(p
, end
);
1482 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub
, resolver
);
1485 uint64_t address
= read_uleb128(p
, end
);
1486 if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR
)
1487 printf("[addr=0x%06llX] ", address
);
1488 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1489 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address
);
1490 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
)
1491 printf("[flags=ABSOLUTE addr=0x%06llX] ", address
);
1493 printf("[flags=0x%llX addr=0x%06llX] ", flags
, address
);
1496 // print child edges
1497 const uint8_t childrenCount
= *p
++;
1498 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1499 const char* edgeName
= (const char*)p
;
1503 uint32_t childNodeOffet
= read_uleb128(p
, end
);
1504 printf("%s->0x%04X", edgeName
, childNodeOffet
);
1505 if ( i
< (childrenCount
-1) )
1515 template <typename A
>
1516 const uint8_t* DyldInfoPrinter
<A
>::printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p
, const uint8_t* end
, uint8_t kind
)
1518 const char* kindStr
= "??";
1520 case DYLD_CACHE_ADJ_V1_POINTER_32
:
1521 kindStr
= "32-bit pointer";
1523 case DYLD_CACHE_ADJ_V1_POINTER_64
:
1524 kindStr
= "64-bit pointer";
1526 case DYLD_CACHE_ADJ_V1_ADRP
:
1527 kindStr
= "arm64 ADRP";
1529 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+0:
1530 kindStr
= "thumb2 movt low high 4 bits=0";
1532 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+1:
1533 kindStr
= "thumb2 movt low high 4 bits=1";
1535 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+2:
1536 kindStr
= "thumb2 movt low high 4 bits=2";
1538 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+3:
1539 kindStr
= "thumb2 movt low high 4 bits=3";
1541 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+4:
1542 kindStr
= "thumb2 movt low high 4 bits=4";
1544 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+5:
1545 kindStr
= "thumb2 movt low high 4 bits=5";
1547 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+6:
1548 kindStr
= "thumb2 movt low high 4 bits=6";
1550 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+7:
1551 kindStr
= "thumb2 movt low high 4 bits=7";
1553 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+8:
1554 kindStr
= "thumb2 movt low high 4 bits=8";
1556 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+9:
1557 kindStr
= "thumb2 movt low high 4 bits=9";
1559 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+10:
1560 kindStr
= "thumb2 movt low high 4 bits=10";
1562 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+11:
1563 kindStr
= "thumb2 movt low high 4 bits=11";
1565 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+12:
1566 kindStr
= "thumb2 movt low high 4 bits=12";
1568 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+13:
1569 kindStr
= "thumb2 movt low high 4 bits=13";
1571 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+14:
1572 kindStr
= "thumb2 movt low high 4 bits=14";
1574 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT
+15:
1575 kindStr
= "thumb2 movt low high 4 bits=15";
1577 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+0:
1578 kindStr
= "arm movt low high 4 bits=0";
1580 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+1:
1581 kindStr
= "arm movt low high 4 bits=1";
1583 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+2:
1584 kindStr
= "arm movt low high 4 bits=2";
1586 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+3:
1587 kindStr
= "arm movt low high 4 bits=3";
1589 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+4:
1590 kindStr
= "arm movt low high 4 bits=4";
1592 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+5:
1593 kindStr
= "arm movt low high 4 bits=5";
1595 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+6:
1596 kindStr
= "arm movt low high 4 bits=6";
1598 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+7:
1599 kindStr
= "arm movt low high 4 bits=7";
1601 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+8:
1602 kindStr
= "arm movt low high 4 bits=8";
1604 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+9:
1605 kindStr
= "arm movt low high 4 bits=9";
1607 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+10:
1608 kindStr
= "arm movt low high 4 bits=10";
1610 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+11:
1611 kindStr
= "arm movt low high 4 bits=11";
1613 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+12:
1614 kindStr
= "arm movt low high 4 bits=12";
1616 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+13:
1617 kindStr
= "arm movt low high 4 bits=13";
1619 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+14:
1620 kindStr
= "arm movt low high 4 bits=14";
1622 case DYLD_CACHE_ADJ_V1_ARM_MOVT
+15:
1623 kindStr
= "arm movt low high 4 bits=15";
1626 kindStr
= "<<unknown>>";
1628 uint64_t address
= 0;
1631 delta
= read_uleb128(p
, end
);
1633 printf("0x%0llX %s\n", address
+fBaseAddress
, kindStr
);
1639 template <typename A
>
1640 void DyldInfoPrinter
<A
>::printSharedRegionInfo()
1642 if ( (fSharedRegionInfo
== NULL
) || (fSharedRegionInfo
->datasize() == 0) ) {
1643 printf("no shared region info\n");
1646 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fSharedRegionInfo
->dataoff();
1647 const uint8_t* infoEnd
= &infoStart
[fSharedRegionInfo
->datasize()];
1648 if ( *infoStart
== DYLD_CACHE_ADJ_V2_FORMAT
) {
1650 // Whole :== <count> FromToSection+
1651 // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
1652 // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
1653 // FromOffset :== <kind> <count> <from-sect-offset-delta>
1654 const uint8_t* p
= infoStart
;
1655 uint64_t sectionCount
= read_uleb128(p
, infoEnd
);
1656 for (uint64_t i
=0; i
< sectionCount
; ++i
) {
1657 uint64_t fromSectionIndex
= read_uleb128(p
, infoEnd
);
1658 uint64_t toSectionIndex
= read_uleb128(p
, infoEnd
);
1659 uint64_t toOffsetCount
= read_uleb128(p
, infoEnd
);
1660 const macho_section
<P
>* fromSection
= fSections
[fromSectionIndex
];
1661 const macho_section
<P
>* toSection
= fSections
[toSectionIndex
];
1662 char fromSectionName
[20];
1663 strncpy(fromSectionName
, fromSection
->sectname(), 16);
1664 fromSectionName
[16] = '\0';
1665 printf("from sect=%s/%s, to sect=%s/%s, count=%lld:\n", fromSection
->segname(), fromSectionName
, toSection
->segname(), toSection
->sectname(), toOffsetCount
);
1666 uint64_t toSectionOffset
= 0;
1667 const char* lastFromSymbol
= NULL
;
1668 for (uint64_t j
=0; j
< toOffsetCount
; ++j
) {
1669 uint64_t toSectionDelta
= read_uleb128(p
, infoEnd
);
1670 uint64_t fromOffsetCount
= read_uleb128(p
, infoEnd
);
1671 toSectionOffset
+= toSectionDelta
;
1672 for (uint64_t k
=0; k
< fromOffsetCount
; ++k
) {
1673 uint64_t kind
= read_uleb128(p
, infoEnd
);
1674 uint64_t fromSectDeltaCount
= read_uleb128(p
, infoEnd
);
1675 uint64_t fromSectionOffset
= 0;
1676 for (uint64_t l
=0; l
< fromSectDeltaCount
; ++l
) {
1677 uint64_t delta
= read_uleb128(p
, infoEnd
);
1678 fromSectionOffset
+= delta
;
1679 uint64_t symbolOffset
;
1680 const char* s
= closestSymbolNameForAddress(fromSection
->addr()+fromSectionOffset
, &symbolOffset
, fromSectionIndex
);
1681 if ( (s
!= lastFromSymbol
) && (s
!= NULL
) )
1682 printf(" %s:\n", s
);
1683 const char* toSymbol
= closestSymbolNameForAddress(toSection
->addr()+toSectionOffset
, &symbolOffset
, toSectionIndex
);
1684 printf(" from addr=0x%0llX %s to addr=0x%0llX", fromSection
->addr()+fromSectionOffset
, sharedRegionKindName(kind
), toSection
->addr()+toSectionOffset
);
1685 if ( toSymbol
!= NULL
) {
1686 if ( symbolOffset
== 0 )
1687 printf(" (%s)", toSymbol
);
1689 printf(" (%s + %lld)", toSymbol
, symbolOffset
);
1699 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
);) {
1700 uint8_t kind
= *p
++;
1701 p
= this->printSharedRegionV1InfoForEachULEB128Address(p
, infoEnd
, kind
);
1707 template <typename A
>
1708 const char* DyldInfoPrinter
<A
>::sharedRegionKindName(uint8_t kind
)
1712 return "<<unknown>>";
1713 case DYLD_CACHE_ADJ_V2_POINTER_32
:
1715 case DYLD_CACHE_ADJ_V2_POINTER_64
:
1717 case DYLD_CACHE_ADJ_V2_DELTA_32
:
1719 case DYLD_CACHE_ADJ_V2_DELTA_64
:
1721 case DYLD_CACHE_ADJ_V2_ARM64_ADRP
:
1723 case DYLD_CACHE_ADJ_V2_ARM64_OFF12
:
1725 case DYLD_CACHE_ADJ_V2_ARM64_BR26
:
1727 case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT
:
1729 case DYLD_CACHE_ADJ_V2_ARM_BR24
:
1731 case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT
:
1733 case DYLD_CACHE_ADJ_V2_THUMB_BR22
:
1735 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32
:
1741 #if SUPPORT_ARCH_arm_any
1743 void DyldInfoPrinter
<arm
>::printFunctionStartLine(uint64_t addr
)
1746 printf("0x%0llX [thumb] %s\n", (addr
& -2), symbolNameForAddress(addr
& -2));
1748 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1752 template <typename A
>
1753 void DyldInfoPrinter
<A
>::printFunctionStartLine(uint64_t addr
)
1755 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1759 template <typename A
>
1760 void DyldInfoPrinter
<A
>::printFunctionStartsInfo()
1762 if ( (fFunctionStartsInfo
== NULL
) || (fFunctionStartsInfo
->datasize() == 0) ) {
1763 printf("no function starts info\n");
1766 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fFunctionStartsInfo
->dataoff();
1767 const uint8_t* infoEnd
= &infoStart
[fFunctionStartsInfo
->datasize()];
1768 uint64_t address
= fBaseAddress
;
1769 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
); ) {
1774 uint8_t byte
= *p
++;
1775 delta
|= ((byte
& 0x7F) << shift
);
1777 if ( byte
< 0x80 ) {
1779 printFunctionStartLine(address
);
1787 template <typename A
>
1788 void DyldInfoPrinter
<A
>::printDylibsInfo()
1790 printf("attributes dependent dylibs\n");
1791 for(typename
std::vector
<const macho_dylib_command
<P
>*>::iterator it
= fDylibLoadCommands
.begin(); it
!= fDylibLoadCommands
.end(); ++it
) {
1792 const macho_dylib_command
<P
>* dylib
= *it
;
1793 const char* attribute
= "";
1794 switch ( dylib
->cmd() ) {
1795 case LC_LOAD_WEAK_DYLIB
:
1796 attribute
= "weak_import";
1798 case LC_REEXPORT_DYLIB
:
1799 attribute
= "re-export";
1801 case LC_LOAD_UPWARD_DYLIB
:
1802 attribute
= "upward";
1804 case LC_LAZY_LOAD_DYLIB
:
1805 attribute
= "lazy_load";
1811 printf(" %-12s %s\n", attribute
, dylib
->name());
1815 template <typename A
>
1816 void DyldInfoPrinter
<A
>::printDRInfo()
1818 if ( fDRInfo
== NULL
) {
1819 printf("no Designated Requirements info\n");
1822 printf("dylibs DRs\n");
1823 const uint8_t* start
= ((uint8_t*)fHeader
+ fDRInfo
->dataoff());
1824 //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
1825 typedef Security::SuperBlob
<Security::kSecCodeMagicDRList
> DRListSuperBlob
;
1826 const DRListSuperBlob
* topBlob
= (DRListSuperBlob
*)start
;
1827 if ( topBlob
->validateBlob(fDRInfo
->datasize()) ) {
1828 if ( topBlob
->count() == fDylibLoadCommands
.size() ) {
1829 for(unsigned i
=0; i
< topBlob
->count(); ++i
) {
1830 printf(" %-20s ", fDylibs
[i
]);
1831 const Security::BlobCore
* item
= topBlob
->find(i
);
1832 if ( item
!= NULL
) {
1833 const uint8_t* itemStart
= (uint8_t*)item
;
1834 const uint8_t* itemEnd
= itemStart
+ item
->length();
1835 for(const uint8_t* p
=itemStart
; p
< itemEnd
; ++p
)
1836 printf("%02X ", *p
);
1839 printf("no DR info");
1845 fprintf(stderr
, "superblob of DRs has a different number of elements than dylib load commands\n");
1849 fprintf(stderr
, "superblob of DRs invalid\n");
1858 template <typename A
>
1859 void DyldInfoPrinter
<A
>::printDataInCode()
1861 if ( fDataInCode
== NULL
) {
1862 printf("no data-in-code info\n");
1865 printf("offset length data-kind\n");
1866 const macho_data_in_code_entry
<P
>* start
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff());
1867 const macho_data_in_code_entry
<P
>* end
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff() + fDataInCode
->datasize());
1868 for (const macho_data_in_code_entry
<P
>* p
=start
; p
< end
; ++p
) {
1869 const char* kindStr
= "???";
1870 switch ( p
->kind() ) {
1875 kindStr
= "jumptable8";
1878 kindStr
= "jumptable16";
1881 kindStr
= "jumptable32";
1884 kindStr
= "jumptable32absolute";
1887 printf("0x%08X 0x%04X %s\n", p
->offset(), p
->length(), kindStr
);
1895 ppc::P::uint_t DyldInfoPrinter
<ppc
>::relocBase()
1897 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1898 return fFirstWritableSegment
->vmaddr();
1900 return fFirstSegment
->vmaddr();
1904 ppc64::P::uint_t DyldInfoPrinter
<ppc64
>::relocBase()
1906 if ( fWriteableSegmentWithAddrOver4G
)
1907 return fFirstWritableSegment
->vmaddr();
1909 return fFirstSegment
->vmaddr();
1913 x86::P::uint_t DyldInfoPrinter
<x86
>::relocBase()
1915 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1916 return fFirstWritableSegment
->vmaddr();
1918 return fFirstSegment
->vmaddr();
1922 x86_64::P::uint_t DyldInfoPrinter
<x86_64
>::relocBase()
1924 return fFirstWritableSegment
->vmaddr();
1927 #if SUPPORT_ARCH_arm_any
1929 arm::P::uint_t DyldInfoPrinter
<arm
>::relocBase()
1931 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1932 return fFirstWritableSegment
->vmaddr();
1934 return fFirstSegment
->vmaddr();
1938 #if SUPPORT_ARCH_arm64
1940 arm64::P::uint_t DyldInfoPrinter
<arm64
>::relocBase()
1942 return fFirstWritableSegment
->vmaddr();
1948 const char* DyldInfoPrinter
<ppc
>::relocTypeName(uint8_t r_type
)
1950 if ( r_type
== GENERIC_RELOC_VANILLA
)
1957 const char* DyldInfoPrinter
<ppc64
>::relocTypeName(uint8_t r_type
)
1959 if ( r_type
== GENERIC_RELOC_VANILLA
)
1966 const char* DyldInfoPrinter
<x86
>::relocTypeName(uint8_t r_type
)
1968 if ( r_type
== GENERIC_RELOC_VANILLA
)
1970 else if ( r_type
== GENERIC_RELOC_PB_LA_PTR
)
1971 return "pb pointer";
1977 const char* DyldInfoPrinter
<x86_64
>::relocTypeName(uint8_t r_type
)
1979 if ( r_type
== X86_64_RELOC_UNSIGNED
)
1985 #if SUPPORT_ARCH_arm_any
1987 const char* DyldInfoPrinter
<arm
>::relocTypeName(uint8_t r_type
)
1989 if ( r_type
== ARM_RELOC_VANILLA
)
1991 else if ( r_type
== ARM_RELOC_PB_LA_PTR
)
1992 return "pb pointer";
1998 #if SUPPORT_ARCH_arm64
2000 const char* DyldInfoPrinter
<arm64
>::relocTypeName(uint8_t r_type
)
2002 if ( r_type
== ARM64_RELOC_UNSIGNED
)
2009 template <typename A
>
2010 void DyldInfoPrinter
<A
>::printRelocRebaseInfo()
2012 if ( fDynamicSymbolTable
== NULL
) {
2013 printf("no classic dynamic symbol table");
2016 printf("rebase information (from local relocation records and indirect symbol table):\n");
2017 printf("segment section address type\n");
2018 // walk all local relocations
2019 pint_t rbase
= relocBase();
2020 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->locreloff());
2021 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nlocrel()];
2022 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2023 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
2024 pint_t addr
= reloc
->r_address() + rbase
;
2025 uint8_t segIndex
= segmentIndexForAddress(addr
);
2026 const char* typeName
= relocTypeName(reloc
->r_type());
2027 const char* segName
= segmentName(segIndex
);
2028 const char* sectName
= sectionName(segIndex
, addr
);
2029 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
2032 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
2033 pint_t addr
= sreloc
->r_address() + rbase
;
2034 uint8_t segIndex
= segmentIndexForAddress(addr
);
2035 const char* typeName
= relocTypeName(sreloc
->r_type());
2036 const char* segName
= segmentName(segIndex
);
2037 const char* sectName
= sectionName(segIndex
, addr
);
2038 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
2041 // look for local non-lazy-pointers
2042 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2043 uint8_t segIndex
= 0;
2044 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
, ++segIndex
) {
2045 const macho_segment_command
<P
>* segCmd
= *segit
;
2046 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2047 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2048 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2049 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2050 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2051 uint32_t indirectOffset
= sect
->reserved1();
2052 uint32_t count
= sect
->size() / sizeof(pint_t
);
2053 for (uint32_t i
=0; i
< count
; ++i
) {
2054 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2055 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
2056 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2057 const char* typeName
= "pointer";
2058 const char* segName
= segmentName(segIndex
);
2059 const char* sectName
= sectionName(segIndex
, addr
);
2060 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
2070 template <typename A
>
2071 void DyldInfoPrinter
<A
>::printSymbolTableExportInfo()
2073 if ( fDynamicSymbolTable
== NULL
) {
2074 printf("no classic dynamic symbol table");
2077 printf("export information (from symbol table):\n");
2078 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
2079 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
2080 const char* flags
= "";
2081 if ( sym
->n_desc() & N_WEAK_DEF
)
2082 flags
= "[weak_def] ";
2084 if ( sym
->n_desc() & N_ARM_THUMB_DEF
)
2086 printf("0x%08llX %s%s\n", sym
->n_value()+thumb
, flags
, &fStrings
[sym
->n_strx()]);
2091 template <typename A
>
2092 const char* DyldInfoPrinter
<A
>::closestSymbolNameForAddress(uint64_t addr
, uint64_t* offset
, uint8_t sectIndex
)
2094 const macho_nlist
<P
>* bestSymbol
= NULL
;
2095 if ( fDynamicSymbolTable
!= NULL
) {
2096 // find closest match in globals
2097 const macho_nlist
<P
>* const globalsStart
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()];
2098 const macho_nlist
<P
>* const globalsEnd
= &globalsStart
[fDynamicSymbolTable
->nextdefsym()];
2099 for (const macho_nlist
<P
>* s
= globalsStart
; s
< globalsEnd
; ++s
) {
2100 if ( (s
->n_type() & N_TYPE
) == N_SECT
) {
2101 if ( (s
->n_value() <= addr
) && ((s
->n_sect() == sectIndex
) || (sectIndex
==0)) ) {
2102 if ( (bestSymbol
== NULL
) || (bestSymbol
->n_value() < s
->n_value()) )
2108 // find closest match in locals
2109 const macho_nlist
<P
>* const localsStart
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()];
2110 const macho_nlist
<P
>* const localsEnd
= &localsStart
[fDynamicSymbolTable
->nlocalsym()];
2111 for (const macho_nlist
<P
>* s
= localsStart
; s
< localsEnd
; ++s
) {
2112 if ( ((s
->n_type() & N_TYPE
) == N_SECT
) && ((s
->n_type() & N_STAB
) == 0) ) {
2113 if ( (s
->n_value() <= addr
) && ((s
->n_sect() == sectIndex
) || (sectIndex
==0)) ) {
2114 if ( (bestSymbol
== NULL
) || (bestSymbol
->n_value() < s
->n_value()) )
2121 // find closest match in locals
2122 const macho_nlist
<P
>* const allStart
= &fSymbols
[0];
2123 const macho_nlist
<P
>* const allEnd
= &fSymbols
[fSymbolCount
];
2124 for (const macho_nlist
<P
>* s
= allStart
; s
< allEnd
; ++s
) {
2125 if ( ((s
->n_type() & N_TYPE
) == N_SECT
) && ((s
->n_type() & N_STAB
) == 0) ) {
2126 if ( (s
->n_value() <= addr
) && ((s
->n_sect() == sectIndex
) || (sectIndex
==0)) ) {
2127 if ( (bestSymbol
== NULL
) || (bestSymbol
->n_value() < s
->n_value()) )
2133 if ( bestSymbol
!= NULL
) {
2134 *offset
= addr
- bestSymbol
->n_value();
2135 return &fStrings
[bestSymbol
->n_strx()];
2141 template <typename A
>
2142 const char* DyldInfoPrinter
<A
>::symbolNameForAddress(uint64_t addr
)
2145 const char* s
= closestSymbolNameForAddress(addr
, &offset
);
2146 if ( (offset
== 0) && (s
!= NULL
) )
2151 template <typename A
>
2152 void DyldInfoPrinter
<A
>::printClassicBindingInfo()
2154 if ( fDynamicSymbolTable
== NULL
) {
2155 printf("no classic dynamic symbol table");
2158 printf("binding information (from relocations and indirect symbol table):\n");
2159 printf("segment section address type weak addend dylib symbol\n");
2160 // walk all external relocations
2161 pint_t rbase
= relocBase();
2162 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->extreloff());
2163 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
2164 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2165 pint_t addr
= reloc
->r_address() + rbase
;
2166 uint32_t symbolIndex
= reloc
->r_symbolnum();
2167 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2168 const char* symbolName
= &fStrings
[sym
->n_strx()];
2169 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
2170 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2171 uint8_t segIndex
= segmentIndexForAddress(addr
);
2172 const char* typeName
= relocTypeName(reloc
->r_type());
2173 const char* segName
= segmentName(segIndex
);
2174 const char* sectName
= sectionName(segIndex
, addr
);
2175 const pint_t
* addressMapped
= mappedAddressForVMAddress(addr
);
2176 int64_t addend
= P::getP(*addressMapped
);
2177 if ( fHeader
->flags() & MH_PREBOUND
) {
2178 // In prebound binaries the content is already pointing to the target.
2179 // To get the addend requires subtracting out the base address it was prebound to.
2180 addend
-= sym
->n_value();
2182 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
2183 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
2185 // look for non-lazy pointers
2186 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2187 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2188 const macho_segment_command
<P
>* segCmd
= *segit
;
2189 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2190 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2191 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2192 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2193 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2194 uint32_t indirectOffset
= sect
->reserved1();
2195 uint32_t count
= sect
->size() / sizeof(pint_t
);
2196 for (uint32_t i
=0; i
< count
; ++i
) {
2197 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2198 if ( symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
2199 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2200 const char* symbolName
= &fStrings
[sym
->n_strx()];
2201 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
2202 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2203 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2204 uint8_t segIndex
= segmentIndexForAddress(addr
);
2205 const char* typeName
= "pointer";
2206 const char* segName
= segmentName(segIndex
);
2207 const char* sectName
= sectionName(segIndex
, addr
);
2209 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
2210 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
2220 template <typename A
>
2221 void DyldInfoPrinter
<A
>::printClassicLazyBindingInfo()
2223 if ( fDynamicSymbolTable
== NULL
) {
2224 printf("no classic dynamic symbol table");
2227 printf("lazy binding information (from section records and indirect symbol table):\n");
2228 printf("segment section address index dylib symbol\n");
2229 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2230 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2231 const macho_segment_command
<P
>* segCmd
= *segit
;
2232 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2233 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2234 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2235 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2236 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2237 uint32_t indirectOffset
= sect
->reserved1();
2238 uint32_t count
= sect
->size() / sizeof(pint_t
);
2239 for (uint32_t i
=0; i
< count
; ++i
) {
2240 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2241 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2242 const char* symbolName
= &fStrings
[sym
->n_strx()];
2243 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2244 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2245 uint8_t segIndex
= segmentIndexForAddress(addr
);
2246 const char* segName
= segmentName(segIndex
);
2247 const char* sectName
= sectionName(segIndex
, addr
);
2248 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2251 else if ( (type
== S_SYMBOL_STUBS
) && (((sect
->flags() & S_ATTR_SELF_MODIFYING_CODE
) != 0)) && (sect
->reserved2() == 5) ) {
2252 // i386 self-modifying stubs
2253 uint32_t indirectOffset
= sect
->reserved1();
2254 uint32_t count
= sect
->size() / 5;
2255 for (uint32_t i
=0; i
< count
; ++i
) {
2256 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2257 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
2258 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2259 const char* symbolName
= &fStrings
[sym
->n_strx()];
2260 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2261 pint_t addr
= sect
->addr() + i
*5;
2262 uint8_t segIndex
= segmentIndexForAddress(addr
);
2263 const char* segName
= segmentName(segIndex
);
2264 const char* sectName
= sectionName(segIndex
, addr
);
2265 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2274 static void dump(const char* path
)
2276 struct stat stat_buf
;
2279 int fd
= ::open(path
, O_RDONLY
, 0);
2281 throw "cannot open file";
2282 if ( ::fstat(fd
, &stat_buf
) != 0 )
2283 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
2284 uint32_t length
= stat_buf
.st_size
;
2285 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
2286 if ( p
== ((uint8_t*)(-1)) )
2287 throw "cannot map file";
2289 const mach_header
* mh
= (mach_header
*)p
;
2290 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2291 const struct fat_header
* fh
= (struct fat_header
*)p
;
2292 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
2293 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2294 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2295 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
2296 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
2297 cpu_type_t cpusubtype
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
);
2298 if ( ((cputype
== sPreferredArch
)
2299 && ((sPreferredSubArch
==0) || (sPreferredSubArch
==cpusubtype
)))
2300 || (sPreferredArch
== 0) ) {
2302 case CPU_TYPE_POWERPC
:
2303 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
2304 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2306 throw "in universal file, ppc slice does not contain ppc mach-o";
2309 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
2310 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2312 throw "in universal file, i386 slice does not contain i386 mach-o";
2314 case CPU_TYPE_POWERPC64
:
2315 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
2316 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2318 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
2320 case CPU_TYPE_X86_64
:
2321 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
2322 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2324 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
2326 #if SUPPORT_ARCH_arm_any
2328 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
2329 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2331 throw "in universal file, arm slice does not contain arm mach-o";
2334 #if SUPPORT_ARCH_arm64
2335 case CPU_TYPE_ARM64
:
2336 if ( DyldInfoPrinter
<arm64
>::validFile(p
+ offset
) )
2337 DyldInfoPrinter
<arm64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2339 throw "in universal file, arm64 slice does not contain arm64 mach-o";
2343 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
2348 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
2349 DyldInfoPrinter
<x86
>::make(p
, length
, path
, false);
2351 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
2352 DyldInfoPrinter
<ppc
>::make(p
, length
, path
, false);
2354 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
2355 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
, false);
2357 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
2358 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
, false);
2360 #if SUPPORT_ARCH_arm_any
2361 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
2362 DyldInfoPrinter
<arm
>::make(p
, length
, path
, false);
2365 #if SUPPORT_ARCH_arm64
2366 else if ( DyldInfoPrinter
<arm64
>::validFile(p
) ) {
2367 DyldInfoPrinter
<arm64
>::make(p
, length
, path
, false);
2371 throw "not a known file type";
2374 catch (const char* msg
) {
2375 throwf("%s in %s", msg
, path
);
2381 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
2382 "\t-dylibs print dependent dylibs\n"
2383 "\t-dr print dependent dylibs and show any recorded DR info\n"
2384 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
2385 "\t-bind print addresses dyld will set based on symbolic lookups\n"
2386 "\t-weak_bind print symbols which dyld must coalesce\n"
2387 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
2388 "\t-export print addresses of all symbols this file exports\n"
2389 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
2390 "\t-function_starts print table of function start addresses\n"
2391 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
2392 "\t-data_in_code print any data-in-code information\n"
2397 int main(int argc
, const char* argv
[])
2405 std::vector
<const char*> files
;
2406 for(int i
=1; i
< argc
; ++i
) {
2407 const char* arg
= argv
[i
];
2408 if ( arg
[0] == '-' ) {
2409 if ( strcmp(arg
, "-arch") == 0 ) {
2410 const char* arch
= ++i
<argc
? argv
[i
]: "";
2411 if ( strcmp(arch
, "ppc64") == 0 )
2412 sPreferredArch
= CPU_TYPE_POWERPC64
;
2413 else if ( strcmp(arch
, "ppc") == 0 )
2414 sPreferredArch
= CPU_TYPE_POWERPC
;
2415 else if ( strcmp(arch
, "i386") == 0 )
2416 sPreferredArch
= CPU_TYPE_I386
;
2417 else if ( strcmp(arch
, "x86_64") == 0 )
2418 sPreferredArch
= CPU_TYPE_X86_64
;
2419 #if SUPPORT_ARCH_arm64
2420 else if ( strcmp(arch
, "arm64") == 0 )
2421 sPreferredArch
= CPU_TYPE_ARM64
;
2425 throw "-arch missing architecture name";
2427 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
2428 if ( strcmp(t
->archName
,arch
) == 0 ) {
2429 sPreferredArch
= t
->cpuType
;
2431 sPreferredSubArch
= t
->cpuSubType
;
2437 throwf("unknown architecture %s", arch
);
2440 else if ( strcmp(arg
, "-rebase") == 0 ) {
2443 else if ( strcmp(arg
, "-bind") == 0 ) {
2446 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
2447 printWeakBind
= true;
2449 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
2450 printLazyBind
= true;
2452 else if ( strcmp(arg
, "-export") == 0 ) {
2455 else if ( strcmp(arg
, "-opcodes") == 0 ) {
2456 printOpcodes
= true;
2458 else if ( strcmp(arg
, "-export_dot") == 0 ) {
2459 printExportGraph
= true;
2461 else if ( strcmp(arg
, "-export_trie_nodes") == 0 ) {
2462 printExportNodes
= true;
2464 else if ( strcmp(arg
, "-shared_region") == 0 ) {
2465 printSharedRegion
= true;
2467 else if ( strcmp(arg
, "-function_starts") == 0 ) {
2468 printFunctionStarts
= true;
2470 else if ( strcmp(arg
, "-dylibs") == 0 ) {
2473 else if ( strcmp(arg
, "-dr") == 0 ) {
2476 else if ( strcmp(arg
, "-data_in_code") == 0 ) {
2477 printDataCode
= true;
2480 throwf("unknown option: %s\n", arg
);
2484 files
.push_back(arg
);
2487 if ( files
.size() == 0 )
2489 if ( files
.size() == 1 ) {
2493 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
2494 printf("\n%s:\n", *it
);
2499 catch (const char* msg
) {
2500 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);