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 void printFunctionStartsInfo();
108 void printDylibsInfo();
110 void printDataInCode();
111 void printFunctionStartLine(uint64_t addr
);
112 const uint8_t* printSharedRegionInfoForEachULEB128Address(const uint8_t* p
, uint8_t kind
);
114 const char* relocTypeName(uint8_t r_type
);
115 uint8_t segmentIndexForAddress(pint_t addr
);
116 void processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
117 const uint8_t* parent
, const uint8_t* p
,
118 char* cummulativeString
, int curStrOffset
);
119 void gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
120 const uint8_t* parent
, const uint8_t* p
,
121 std::vector
<uint32_t>& nodeStarts
);
122 const char* rebaseTypeName(uint8_t type
);
123 const char* bindTypeName(uint8_t type
);
124 pint_t
segStartAddress(uint8_t segIndex
);
125 const char* segmentName(uint8_t segIndex
);
126 const char* sectionName(uint8_t segIndex
, pint_t address
);
127 const char* getSegAndSectName(uint8_t segIndex
, pint_t address
);
128 const char* ordinalName(int libraryOrdinal
);
129 const char* classicOrdinalName(int libraryOrdinal
);
130 pint_t
* mappedAddressForVMAddress(pint_t vmaddress
);
131 const char* symbolNameForAddress(uint64_t);
135 const macho_header
<P
>* fHeader
;
137 const char* fStrings
;
138 const char* fStringsEnd
;
139 const macho_nlist
<P
>* fSymbols
;
140 uint32_t fSymbolCount
;
141 const macho_dyld_info_command
<P
>* fInfo
;
142 const macho_linkedit_data_command
<P
>* fSharedRegionInfo
;
143 const macho_linkedit_data_command
<P
>* fFunctionStartsInfo
;
144 const macho_linkedit_data_command
<P
>* fDataInCode
;
145 const macho_linkedit_data_command
<P
>* fDRInfo
;
146 uint64_t fBaseAddress
;
147 const macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
148 const macho_segment_command
<P
>* fFirstSegment
;
149 const macho_segment_command
<P
>* fFirstWritableSegment
;
150 bool fWriteableSegmentWithAddrOver4G
;
151 std::vector
<const macho_segment_command
<P
>*>fSegments
;
152 std::vector
<const char*> fDylibs
;
153 std::vector
<const macho_dylib_command
<P
>*> fDylibLoadCommands
;
159 bool DyldInfoPrinter
<ppc
>::validFile(const uint8_t* fileContent
)
161 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
162 if ( header
->magic() != MH_MAGIC
)
164 if ( header
->cputype() != CPU_TYPE_POWERPC
)
166 switch (header
->filetype()) {
178 bool DyldInfoPrinter
<ppc64
>::validFile(const uint8_t* fileContent
)
180 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
181 if ( header
->magic() != MH_MAGIC_64
)
183 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
185 switch (header
->filetype()) {
197 bool DyldInfoPrinter
<x86
>::validFile(const uint8_t* fileContent
)
199 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
200 if ( header
->magic() != MH_MAGIC
)
202 if ( header
->cputype() != CPU_TYPE_I386
)
204 switch (header
->filetype()) {
216 bool DyldInfoPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
218 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
219 if ( header
->magic() != MH_MAGIC_64
)
221 if ( header
->cputype() != CPU_TYPE_X86_64
)
223 switch (header
->filetype()) {
234 #if SUPPORT_ARCH_arm_any
236 bool DyldInfoPrinter
<arm
>::validFile(const uint8_t* fileContent
)
238 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
239 if ( header
->magic() != MH_MAGIC
)
241 if ( header
->cputype() != CPU_TYPE_ARM
)
243 switch (header
->filetype()) {
255 #if SUPPORT_ARCH_arm64
257 bool DyldInfoPrinter
<arm64
>::validFile(const uint8_t* fileContent
)
259 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
260 if ( header
->magic() != MH_MAGIC_64
)
262 if ( header
->cputype() != CPU_TYPE_ARM64
)
264 switch (header
->filetype()) {
275 template <typename A
>
276 DyldInfoPrinter
<A
>::DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
277 : fHeader(NULL
), fLength(fileLength
),
278 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fInfo(NULL
),
279 fSharedRegionInfo(NULL
), fFunctionStartsInfo(NULL
), fDataInCode(NULL
), fDRInfo(NULL
),
280 fBaseAddress(0), fDynamicSymbolTable(NULL
), fFirstSegment(NULL
), fFirstWritableSegment(NULL
),
281 fWriteableSegmentWithAddrOver4G(false)
284 if ( ! validFile(fileContent
) )
285 throw "not a mach-o file that can be checked";
287 fPath
= strdup(path
);
288 fHeader
= (const macho_header
<P
>*)fileContent
;
291 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
292 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
293 const uint32_t cmd_count
= fHeader
->ncmds();
294 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
295 const macho_load_command
<P
>* cmd
= cmds
;
296 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
297 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
298 if ( endOfCmd
> endOfLoadCommands
)
299 throwf("load command #%d extends beyond the end of the load commands", i
);
300 if ( endOfCmd
> endOfFile
)
301 throwf("load command #%d extends beyond the end of the file", i
);
302 switch ( cmd
->cmd() ) {
304 case LC_DYLD_INFO_ONLY
:
305 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
307 case macho_segment_command
<P
>::CMD
:
309 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
310 fSegments
.push_back(segCmd
);
311 if ( (segCmd
->fileoff() == 0) && (segCmd
->filesize() != 0) )
312 fBaseAddress
= segCmd
->vmaddr();
313 if ( fFirstSegment
== NULL
)
314 fFirstSegment
= segCmd
;
315 if ( (segCmd
->initprot() & VM_PROT_WRITE
) != 0 ) {
316 if ( fFirstWritableSegment
== NULL
)
317 fFirstWritableSegment
= segCmd
;
318 if ( segCmd
->vmaddr() > 0x100000000ULL
)
319 fWriteableSegmentWithAddrOver4G
= true;
324 case LC_LOAD_WEAK_DYLIB
:
325 case LC_REEXPORT_DYLIB
:
326 case LC_LOAD_UPWARD_DYLIB
:
327 case LC_LAZY_LOAD_DYLIB
:
329 const macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
330 fDylibLoadCommands
.push_back(dylib
);
331 const char* lastSlash
= strrchr(dylib
->name(), '/');
332 const char* leafName
= (lastSlash
!= NULL
) ? lastSlash
+1 : dylib
->name();
333 const char* firstDot
= strchr(leafName
, '.');
334 if ( firstDot
!= NULL
) {
335 char* t
= strdup(leafName
);
336 t
[firstDot
-leafName
] = '\0';
337 fDylibs
.push_back(t
);
340 fDylibs
.push_back(leafName
);
345 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
349 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
350 fSymbolCount
= symtab
->nsyms();
351 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
352 fStrings
= (char*)fHeader
+ symtab
->stroff();
353 fStringsEnd
= fStrings
+ symtab
->strsize();
356 case LC_SEGMENT_SPLIT_INFO
:
357 fSharedRegionInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
359 case LC_FUNCTION_STARTS
:
360 fFunctionStartsInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
362 case LC_DATA_IN_CODE
:
363 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
365 case LC_DYLIB_CODE_SIGN_DRS
:
366 fDRInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
369 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
373 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
374 if ( (cpu_type_t
)fHeader
->cputype() == t
->cpuType
) {
375 if ( t
->isSubType
&& ((cpu_subtype_t
)fHeader
->cpusubtype() != t
->cpuSubType
) )
377 printf("for arch %s:\n", t
->archName
);
386 printRelocRebaseInfo();
392 printClassicBindingInfo();
395 printWeakBindingInfo();
396 if ( printLazyBind
) {
398 printLazyBindingInfo();
400 printClassicLazyBindingInfo();
406 printSymbolTableExportInfo();
408 if ( printOpcodes
) {
409 printRebaseInfoOpcodes();
410 printBindingInfoOpcodes(false);
411 printBindingInfoOpcodes(true);
412 printLazyBindingOpcodes();
414 if ( printExportGraph
)
415 printExportInfoGraph();
416 if ( printExportNodes
)
417 printExportInfoNodes();
418 if ( printSharedRegion
)
419 printSharedRegionInfo();
420 if ( printFunctionStarts
)
421 printFunctionStartsInfo();
430 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
436 throwf("malformed uleb128");
438 uint64_t slice
= *p
& 0x7f;
440 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
441 throwf("uleb128 too big");
443 result
|= (slice
<< bit
);
451 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
458 throwf("malformed sleb128");
460 result
|= (((int64_t)(byte
& 0x7f)) << bit
);
462 } while (byte
& 0x80);
463 // sign extend negative numbers
464 if ( (byte
& 0x40) != 0 )
465 result
|= (-1LL) << bit
;
470 template <typename A
>
471 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
474 case REBASE_TYPE_POINTER
:
476 case REBASE_TYPE_TEXT_ABSOLUTE32
:
478 case REBASE_TYPE_TEXT_PCREL32
:
481 return "!!unknown!!";
485 template <typename A
>
486 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
489 case BIND_TYPE_POINTER
:
491 case BIND_TYPE_TEXT_ABSOLUTE32
:
493 case BIND_TYPE_TEXT_PCREL32
:
496 return "!!unknown!!";
500 template <typename A
>
501 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
503 if ( segIndex
> fSegments
.size() )
504 throw "segment index out of range";
505 return fSegments
[segIndex
]->vmaddr();
508 template <typename A
>
509 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
511 if ( segIndex
> fSegments
.size() )
512 throw "segment index out of range";
513 return fSegments
[segIndex
]->segname();
516 template <typename A
>
517 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
519 if ( segIndex
> fSegments
.size() )
520 throw "segment index out of range";
521 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
522 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
523 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
524 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
525 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
526 if ( strlen(sect
->sectname()) > 15 ) {
527 static char temp
[18];
528 strlcpy(temp
, sect
->sectname(), 17);
532 return sect
->sectname();
539 template <typename A
>
540 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
542 static char buffer
[64];
543 strcpy(buffer
, segmentName(segIndex
));
545 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
546 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
547 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
548 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
549 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
550 // section name may not be zero terminated
551 char* end
= &buffer
[strlen(buffer
)];
552 strlcpy(end
, sect
->sectname(), 16);
559 template <typename A
>
560 uint8_t DyldInfoPrinter
<A
>::segmentIndexForAddress(pint_t address
)
562 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
563 if ( (fSegments
[i
]->vmaddr() <= address
) && (address
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
567 throwf("address 0x%llX is not in any segment", (uint64_t)address
);
570 template <typename A
>
571 typename
A::P::uint_t
* DyldInfoPrinter
<A
>::mappedAddressForVMAddress(pint_t vmaddress
)
573 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
574 if ( (fSegments
[i
]->vmaddr() <= vmaddress
) && (vmaddress
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
575 unsigned long offsetInMappedFile
= fSegments
[i
]->fileoff()+vmaddress
-fSegments
[i
]->vmaddr();
576 return (pint_t
*)((uint8_t*)fHeader
+ offsetInMappedFile
);
579 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress
);
582 template <typename A
>
583 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
585 switch ( libraryOrdinal
) {
586 case BIND_SPECIAL_DYLIB_SELF
:
588 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
589 return "main-executable";
590 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
591 return "flat-namespace";
593 if ( libraryOrdinal
< BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
594 throw "unknown special ordinal";
595 if ( libraryOrdinal
> (int)fDylibs
.size() )
596 throw "libraryOrdinal out of range";
597 return fDylibs
[libraryOrdinal
-1];
600 template <typename A
>
601 const char* DyldInfoPrinter
<A
>::classicOrdinalName(int libraryOrdinal
)
603 if ( (fHeader
->flags() & MH_TWOLEVEL
) == 0 )
604 return "flat-namespace";
605 switch ( libraryOrdinal
) {
606 case SELF_LIBRARY_ORDINAL
:
608 case EXECUTABLE_ORDINAL
:
609 return "main-executable";
610 case DYNAMIC_LOOKUP_ORDINAL
:
611 return "flat-namespace";
613 if ( libraryOrdinal
> (int)fDylibs
.size() )
614 throw "libraryOrdinal out of range";
615 return fDylibs
[libraryOrdinal
-1];
618 template <typename A
>
619 void DyldInfoPrinter
<A
>::printRebaseInfo()
621 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
622 printf("no compressed rebase info\n");
625 printf("rebase information (from compressed dyld info):\n");
626 printf("segment section address type\n");
628 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
629 const uint8_t* end
= &p
[fInfo
->rebase_size()];
632 uint64_t segOffset
= 0;
636 pint_t segStartAddr
= 0;
637 const char* segName
= "??";
638 const char* typeName
= "??";
640 while ( !done
&& (p
< end
) ) {
641 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
642 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
645 case REBASE_OPCODE_DONE
:
648 case REBASE_OPCODE_SET_TYPE_IMM
:
650 typeName
= rebaseTypeName(type
);
652 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
653 segIndex
= immediate
;
654 segStartAddr
= segStartAddress(segIndex
);
655 segName
= segmentName(segIndex
);
656 segOffset
= read_uleb128(p
, end
);
658 case REBASE_OPCODE_ADD_ADDR_ULEB
:
659 segOffset
+= read_uleb128(p
, end
);
661 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
662 segOffset
+= immediate
*sizeof(pint_t
);
664 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
665 for (int i
=0; i
< immediate
; ++i
) {
666 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
667 segOffset
+= sizeof(pint_t
);
670 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
671 count
= read_uleb128(p
, end
);
672 for (uint32_t i
=0; i
< count
; ++i
) {
673 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
674 segOffset
+= sizeof(pint_t
);
677 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
678 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
679 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
681 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
682 count
= read_uleb128(p
, end
);
683 skip
= read_uleb128(p
, end
);
684 for (uint32_t i
=0; i
< count
; ++i
) {
685 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
686 segOffset
+= skip
+ sizeof(pint_t
);
690 throwf("bad rebase opcode %d", *p
);
699 template <typename A
>
700 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
702 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
703 printf("no compressed rebase info\n");
706 printf("rebase opcodes:\n");
707 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
708 const uint8_t* end
= &p
[fInfo
->rebase_size()];
711 uint64_t address
= fBaseAddress
;
714 unsigned int segmentIndex
;
716 while ( !done
&& (p
< end
) ) {
717 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
718 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
721 case REBASE_OPCODE_DONE
:
723 printf("REBASE_OPCODE_DONE()\n");
725 case REBASE_OPCODE_SET_TYPE_IMM
:
727 printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type
);
729 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
730 segmentIndex
= immediate
;
731 address
= read_uleb128(p
, end
);
732 printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex
, address
);
734 case REBASE_OPCODE_ADD_ADDR_ULEB
:
735 address
= read_uleb128(p
, end
);
736 printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address
);
738 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
739 address
= immediate
*sizeof(pint_t
);
740 printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address
);
742 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
743 printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate
);
745 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
746 count
= read_uleb128(p
, end
);
747 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count
);
749 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
750 skip
= read_uleb128(p
, end
) + sizeof(pint_t
);
751 printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip
);
753 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
754 count
= read_uleb128(p
, end
);
755 skip
= read_uleb128(p
, end
);
756 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count
, skip
);
759 throwf("bad rebase opcode %d", *p
);
771 template <typename A
>
772 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
774 if ( fInfo
== NULL
) {
775 printf("no compressed binding info\n");
777 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
778 printf("no compressed binding info\n");
780 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
781 printf("no compressed weak binding info\n");
784 const uint8_t* start
;
787 printf("weak binding opcodes:\n");
788 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
789 end
= &start
[fInfo
->weak_bind_size()];
792 printf("binding opcodes:\n");
793 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
794 end
= &start
[fInfo
->bind_size()];
796 const uint8_t* p
= start
;
799 uint64_t address
= fBaseAddress
;
800 const char* symbolName
= NULL
;
801 int libraryOrdinal
= 0;
803 uint32_t segmentIndex
= 0;
807 while ( !done
&& (p
< end
) ) {
808 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
809 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
810 uint32_t opcodeOffset
= p
-start
;
813 case BIND_OPCODE_DONE
:
815 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
817 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
818 libraryOrdinal
= immediate
;
819 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
821 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
822 libraryOrdinal
= read_uleb128(p
, end
);
823 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
825 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
826 // the special ordinals are negative numbers
827 if ( immediate
== 0 )
830 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
831 libraryOrdinal
= signExtended
;
833 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
835 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
837 symbolName
= (char*)p
;
841 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
843 case BIND_OPCODE_SET_TYPE_IMM
:
845 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
847 case BIND_OPCODE_SET_ADDEND_SLEB
:
848 addend
= read_sleb128(p
, end
);
849 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
851 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
852 segmentIndex
= immediate
;
853 address
= read_uleb128(p
, end
);
854 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
856 case BIND_OPCODE_ADD_ADDR_ULEB
:
857 skip
= read_uleb128(p
, end
);
858 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
860 case BIND_OPCODE_DO_BIND
:
861 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
863 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
864 skip
= read_uleb128(p
, end
);
865 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
867 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
868 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
869 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
871 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
872 count
= read_uleb128(p
, end
);
873 skip
= read_uleb128(p
, end
);
874 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
877 throwf("unknown bind opcode %d", *p
);
886 template <typename A
>
887 void DyldInfoPrinter
<A
>::printBindingInfo()
889 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
890 printf("no compressed binding info\n");
893 printf("bind information:\n");
894 printf("segment section address type addend dylib symbol\n");
895 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->bind_off();
896 const uint8_t* end
= &p
[fInfo
->bind_size()];
899 uint8_t segIndex
= 0;
900 uint64_t segOffset
= 0;
901 const char* symbolName
= NULL
;
902 const char* fromDylib
= "??";
903 int libraryOrdinal
= 0;
907 pint_t segStartAddr
= 0;
908 const char* segName
= "??";
909 const char* typeName
= "??";
910 const char* weak_import
= "";
912 while ( !done
&& (p
< end
) ) {
913 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
914 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
917 case BIND_OPCODE_DONE
:
920 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
921 libraryOrdinal
= immediate
;
922 fromDylib
= ordinalName(libraryOrdinal
);
924 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
925 libraryOrdinal
= read_uleb128(p
, end
);
926 fromDylib
= ordinalName(libraryOrdinal
);
928 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
929 // the special ordinals are negative numbers
930 if ( immediate
== 0 )
933 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
934 libraryOrdinal
= signExtended
;
936 fromDylib
= ordinalName(libraryOrdinal
);
938 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
939 symbolName
= (char*)p
;
943 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
944 weak_import
= " (weak import)";
948 case BIND_OPCODE_SET_TYPE_IMM
:
950 typeName
= bindTypeName(type
);
952 case BIND_OPCODE_SET_ADDEND_SLEB
:
953 addend
= read_sleb128(p
, end
);
955 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
956 segIndex
= immediate
;
957 segStartAddr
= segStartAddress(segIndex
);
958 segName
= segmentName(segIndex
);
959 segOffset
= read_uleb128(p
, end
);
961 case BIND_OPCODE_ADD_ADDR_ULEB
:
962 segOffset
+= read_uleb128(p
, end
);
964 case BIND_OPCODE_DO_BIND
:
965 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
966 segOffset
+= sizeof(pint_t
);
968 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
969 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
970 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
972 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
973 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
974 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
976 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
977 count
= read_uleb128(p
, end
);
978 skip
= read_uleb128(p
, end
);
979 for (uint32_t i
=0; i
< count
; ++i
) {
980 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
981 segOffset
+= skip
+ sizeof(pint_t
);
985 throwf("bad bind opcode %d", *p
);
992 template <typename A
>
993 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
995 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
996 printf("no weak binding\n");
999 printf("weak binding information:\n");
1000 printf("segment section address type addend symbol\n");
1001 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
1002 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
1005 uint8_t segIndex
= 0;
1006 uint64_t segOffset
= 0;
1007 const char* symbolName
= NULL
;
1011 pint_t segStartAddr
= 0;
1012 const char* segName
= "??";
1013 const char* typeName
= "??";
1015 while ( !done
&& (p
< end
) ) {
1016 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1017 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1020 case BIND_OPCODE_DONE
:
1023 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1024 symbolName
= (char*)p
;
1028 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
1029 printf(" strong %s\n", symbolName
);
1031 case BIND_OPCODE_SET_TYPE_IMM
:
1033 typeName
= bindTypeName(type
);
1035 case BIND_OPCODE_SET_ADDEND_SLEB
:
1036 addend
= read_sleb128(p
, end
);
1038 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1039 segIndex
= immediate
;
1040 segStartAddr
= segStartAddress(segIndex
);
1041 segName
= segmentName(segIndex
);
1042 segOffset
= read_uleb128(p
, end
);
1044 case BIND_OPCODE_ADD_ADDR_ULEB
:
1045 segOffset
+= read_uleb128(p
, end
);
1047 case BIND_OPCODE_DO_BIND
:
1048 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1049 segOffset
+= sizeof(pint_t
);
1051 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1052 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1053 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1055 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1056 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1057 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1059 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1060 count
= read_uleb128(p
, end
);
1061 skip
= read_uleb128(p
, end
);
1062 for (uint32_t i
=0; i
< count
; ++i
) {
1063 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1064 segOffset
+= skip
+ sizeof(pint_t
);
1068 throwf("unknown weak bind opcode %d", *p
);
1076 template <typename A
>
1077 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
1079 if ( fInfo
== NULL
) {
1080 printf("no compressed dyld info\n");
1082 else if ( fInfo
->lazy_bind_off() == 0 ) {
1083 printf("no compressed lazy binding info\n");
1086 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1087 printf("segment section address index dylib symbol\n");
1088 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1089 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1091 uint8_t type
= BIND_TYPE_POINTER
;
1092 uint8_t segIndex
= 0;
1093 uint64_t segOffset
= 0;
1094 const char* symbolName
= NULL
;
1095 const char* fromDylib
= "??";
1096 int libraryOrdinal
= 0;
1098 uint32_t lazy_offset
= 0;
1099 pint_t segStartAddr
= 0;
1100 const char* segName
= "??";
1101 const char* typeName
= "??";
1102 const char* weak_import
= "";
1103 for (const uint8_t* p
=start
; p
< end
; ) {
1104 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1105 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1108 case BIND_OPCODE_DONE
:
1109 lazy_offset
= p
-start
;
1111 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1112 libraryOrdinal
= immediate
;
1113 fromDylib
= ordinalName(libraryOrdinal
);
1115 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1116 libraryOrdinal
= read_uleb128(p
, end
);
1117 fromDylib
= ordinalName(libraryOrdinal
);
1119 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1120 // the special ordinals are negative numbers
1121 if ( immediate
== 0 )
1124 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1125 libraryOrdinal
= signExtended
;
1127 fromDylib
= ordinalName(libraryOrdinal
);
1129 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1130 symbolName
= (char*)p
;
1134 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
1135 weak_import
= " (weak import)";
1139 case BIND_OPCODE_SET_TYPE_IMM
:
1141 typeName
= bindTypeName(type
);
1143 case BIND_OPCODE_SET_ADDEND_SLEB
:
1144 addend
= read_sleb128(p
, end
);
1146 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1147 segIndex
= immediate
;
1148 segStartAddr
= segStartAddress(segIndex
);
1149 segName
= segmentName(segIndex
);
1150 segOffset
= read_uleb128(p
, end
);
1152 case BIND_OPCODE_ADD_ADDR_ULEB
:
1153 segOffset
+= read_uleb128(p
, end
);
1155 case BIND_OPCODE_DO_BIND
:
1156 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
, weak_import
);
1157 segOffset
+= sizeof(pint_t
);
1160 throwf("bad lazy bind opcode %d", *p
);
1167 template <typename A
>
1168 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1170 if ( fInfo
== NULL
) {
1171 printf("no compressed dyld info\n");
1173 else if ( fInfo
->lazy_bind_off() == 0 ) {
1174 printf("no compressed lazy binding info\n");
1177 printf("lazy binding opcodes:\n");
1178 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1179 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1180 uint8_t type
= BIND_TYPE_POINTER
;
1182 uint64_t address
= fBaseAddress
;
1183 const char* symbolName
= NULL
;
1184 int libraryOrdinal
= 0;
1186 uint32_t segmentIndex
= 0;
1189 for (const uint8_t* p
= start
; p
< end
; ) {
1190 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1191 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1192 uint32_t opcodeOffset
= p
-start
;
1195 case BIND_OPCODE_DONE
:
1196 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1198 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1199 libraryOrdinal
= immediate
;
1200 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1202 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1203 libraryOrdinal
= read_uleb128(p
, end
);
1204 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1206 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1207 // the special ordinals are negative numbers
1208 if ( immediate
== 0 )
1211 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1212 libraryOrdinal
= signExtended
;
1214 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1216 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1218 symbolName
= (char*)p
;
1222 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1224 case BIND_OPCODE_SET_TYPE_IMM
:
1226 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1228 case BIND_OPCODE_SET_ADDEND_SLEB
:
1229 addend
= read_sleb128(p
, end
);
1230 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1232 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1233 segmentIndex
= immediate
;
1234 address
= read_uleb128(p
, end
);
1235 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1237 case BIND_OPCODE_ADD_ADDR_ULEB
:
1238 skip
= read_uleb128(p
, end
);
1239 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1241 case BIND_OPCODE_DO_BIND
:
1242 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1244 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1245 skip
= read_uleb128(p
, end
);
1246 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1248 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1249 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1250 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1252 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1253 count
= read_uleb128(p
, end
);
1254 skip
= read_uleb128(p
, end
);
1255 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1258 throwf("unknown bind opcode %d", *p
);
1265 struct SortExportsByAddress
1267 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1269 return ( left
.address
< right
.address
);
1273 template <typename A
>
1274 void DyldInfoPrinter
<A
>::printExportInfo()
1276 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1277 printf("no compressed export info\n");
1280 printf("export information (from trie):\n");
1281 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1282 const uint8_t* end
= &start
[fInfo
->export_size()];
1283 std::vector
<mach_o::trie::Entry
> list
;
1284 parseTrie(start
, end
, list
);
1285 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1286 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1287 const bool reExport
= (it
->flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
);
1288 const bool weakDef
= (it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
);
1289 const bool threadLocal
= ((it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
);
1290 const bool abs
= ((it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
);
1291 const bool resolver
= (it
->flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
);
1293 printf("[re-export] ");
1295 printf("0x%08llX ", fBaseAddress
+it
->address
);
1296 printf("%s", it
->name
);
1297 if ( weakDef
|| threadLocal
|| resolver
|| abs
) {
1298 bool needComma
= false;
1304 if ( threadLocal
) {
1307 printf("per-thread");
1319 printf("resolver=0x%08llX", it
->other
);
1325 if ( it
->importName
[0] == '\0' )
1326 printf(" (from %s)", fDylibs
[it
->other
- 1]);
1328 printf(" (%s from %s)", it
->importName
, fDylibs
[it
->other
- 1]);
1336 template <typename A
>
1337 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1338 const uint8_t* parent
, const uint8_t* p
,
1339 char* cummulativeString
, int curStrOffset
)
1341 const uint8_t* const me
= p
;
1342 const uint64_t terminalSize
= read_uleb128(p
, end
);
1343 const uint8_t* children
= p
+ terminalSize
;
1344 if ( terminalSize
!= 0 ) {
1345 uint32_t flags
= read_uleb128(p
, end
);
1346 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1347 uint64_t ordinal
= read_uleb128(p
, end
);
1348 const char* importName
= (const char*)p
;
1352 if ( *importName
== '\0' )
1353 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, ordinal
);
1355 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, importName
, ordinal
);
1358 uint64_t address
= read_uleb128(p
, end
);
1359 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1360 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
1361 read_uleb128(p
, end
);
1365 printf("\tnode%03ld;\n", (long)(me
-start
));
1367 const uint8_t childrenCount
= *children
++;
1368 const uint8_t* s
= children
;
1369 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1370 const char* edgeName
= (char*)s
;
1372 while (*s
!= '\0') {
1373 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1376 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1377 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1378 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1379 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1383 template <typename A
>
1384 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1386 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1387 printf("no compressed export info\n");
1390 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1391 const uint8_t* end
= &p
[fInfo
->export_size()];
1392 char cummulativeString
[2000];
1393 printf("digraph {\n");
1394 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1399 template <typename A
>
1400 void DyldInfoPrinter
<A
>::gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
1401 const uint8_t* parent
, const uint8_t* p
,
1402 std::vector
<uint32_t>& nodeStarts
)
1404 nodeStarts
.push_back(p
-start
);
1405 const uint8_t terminalSize
= read_uleb128(p
, end
);
1406 const uint8_t* children
= p
+ terminalSize
;
1408 const uint8_t childrenCount
= *children
++;
1409 const uint8_t* s
= children
;
1410 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1411 // skip over edge string
1415 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1416 gatherNodeStarts(start
, end
, start
, start
+childNodeOffet
, nodeStarts
);
1421 template <typename A
>
1422 void DyldInfoPrinter
<A
>::printExportInfoNodes()
1424 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1425 printf("no compressed export info\n");
1428 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1429 const uint8_t* end
= &start
[fInfo
->export_size()];
1430 std::vector
<uint32_t> nodeStarts
;
1431 gatherNodeStarts(start
, end
, start
, start
, nodeStarts
);
1432 std::sort(nodeStarts
.begin(), nodeStarts
.end());
1433 for (std::vector
<uint32_t>::const_iterator it
=nodeStarts
.begin(); it
!= nodeStarts
.end(); ++it
) {
1434 printf("0x%04X: ", *it
);
1435 const uint8_t* p
= start
+ *it
;
1436 uint64_t exportInfoSize
= read_uleb128(p
, end
);
1437 if ( exportInfoSize
!= 0 ) {
1438 // print terminal info
1439 uint64_t flags
= read_uleb128(p
, end
);
1440 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1441 uint64_t ordinal
= read_uleb128(p
, end
);
1442 const char* importName
= (const char*)p
;
1446 if ( strlen(importName
) == 0 )
1447 printf("[flags=REEXPORT ordinal=%llu] ", ordinal
);
1449 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal
, importName
);
1451 else if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1452 uint64_t stub
= read_uleb128(p
, end
);
1453 uint64_t resolver
= read_uleb128(p
, end
);
1454 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub
, resolver
);
1457 uint64_t address
= read_uleb128(p
, end
);
1458 if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR
)
1459 printf("[addr=0x%06llX] ", address
);
1460 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1461 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address
);
1462 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
)
1463 printf("[flags=ABSOLUTE addr=0x%06llX] ", address
);
1465 printf("[flags=0x%llX addr=0x%06llX] ", flags
, address
);
1468 // print child edges
1469 const uint8_t childrenCount
= *p
++;
1470 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1471 const char* edgeName
= (const char*)p
;
1475 uint32_t childNodeOffet
= read_uleb128(p
, end
);
1476 printf("%s->0x%04X", edgeName
, childNodeOffet
);
1477 if ( i
< (childrenCount
-1) )
1487 template <typename A
>
1488 const uint8_t* DyldInfoPrinter
<A
>::printSharedRegionInfoForEachULEB128Address(const uint8_t* p
, uint8_t kind
)
1490 const char* kindStr
= "??";
1493 kindStr
= "32-bit pointer";
1496 kindStr
= "64-bit pointer";
1499 #if SUPPORT_ARCH_arm64
1500 if ( fHeader
->cputype() == CPU_TYPE_ARM64
)
1501 kindStr
= "arm64 ADRP";
1504 kindStr
= "ppc hi16";
1507 kindStr
= "32-bit offset to IMPORT";
1510 kindStr
= "thumb2 movw";
1513 kindStr
= "ARM movw";
1516 kindStr
= "thumb2 movt low high 4 bits=0";
1519 kindStr
= "thumb2 movt low high 4 bits=1";
1522 kindStr
= "thumb2 movt low high 4 bits=2";
1525 kindStr
= "thumb2 movt low high 4 bits=3";
1528 kindStr
= "thumb2 movt low high 4 bits=4";
1531 kindStr
= "thumb2 movt low high 4 bits=5";
1534 kindStr
= "thumb2 movt low high 4 bits=6";
1537 kindStr
= "thumb2 movt low high 4 bits=7";
1540 kindStr
= "thumb2 movt low high 4 bits=8";
1543 kindStr
= "thumb2 movt low high 4 bits=9";
1546 kindStr
= "thumb2 movt low high 4 bits=0xA";
1549 kindStr
= "thumb2 movt low high 4 bits=0xB";
1552 kindStr
= "thumb2 movt low high 4 bits=0xC";
1555 kindStr
= "thumb2 movt low high 4 bits=0xD";
1558 kindStr
= "thumb2 movt low high 4 bits=0xE";
1561 kindStr
= "thumb2 movt low high 4 bits=0xF";
1564 uint64_t address
= 0;
1569 uint8_t byte
= *p
++;
1570 delta
|= ((byte
& 0x7F) << shift
);
1572 if ( byte
< 0x80 ) {
1575 printf("0x%0llX %s\n", address
+fBaseAddress
, kindStr
);
1587 template <typename A
>
1588 void DyldInfoPrinter
<A
>::printSharedRegionInfo()
1590 if ( (fSharedRegionInfo
== NULL
) || (fSharedRegionInfo
->datasize() == 0) ) {
1591 printf("no shared region info\n");
1594 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fSharedRegionInfo
->dataoff();
1595 const uint8_t* infoEnd
= &infoStart
[fSharedRegionInfo
->datasize()];
1596 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
);) {
1597 uint8_t kind
= *p
++;
1598 p
= this->printSharedRegionInfoForEachULEB128Address(p
, kind
);
1604 #if SUPPORT_ARCH_arm_any
1606 void DyldInfoPrinter
<arm
>::printFunctionStartLine(uint64_t addr
)
1609 printf("0x%0llX [thumb] %s\n", (addr
& -2), symbolNameForAddress(addr
& -2));
1611 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1615 template <typename A
>
1616 void DyldInfoPrinter
<A
>::printFunctionStartLine(uint64_t addr
)
1618 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1622 template <typename A
>
1623 void DyldInfoPrinter
<A
>::printFunctionStartsInfo()
1625 if ( (fFunctionStartsInfo
== NULL
) || (fFunctionStartsInfo
->datasize() == 0) ) {
1626 printf("no function starts info\n");
1629 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fFunctionStartsInfo
->dataoff();
1630 const uint8_t* infoEnd
= &infoStart
[fFunctionStartsInfo
->datasize()];
1631 uint64_t address
= fBaseAddress
;
1632 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
); ) {
1637 uint8_t byte
= *p
++;
1638 delta
|= ((byte
& 0x7F) << shift
);
1640 if ( byte
< 0x80 ) {
1642 printFunctionStartLine(address
);
1650 template <typename A
>
1651 void DyldInfoPrinter
<A
>::printDylibsInfo()
1653 printf("attributes dependent dylibs\n");
1654 for(typename
std::vector
<const macho_dylib_command
<P
>*>::iterator it
= fDylibLoadCommands
.begin(); it
!= fDylibLoadCommands
.end(); ++it
) {
1655 const macho_dylib_command
<P
>* dylib
= *it
;
1656 const char* attribute
= "";
1657 switch ( dylib
->cmd() ) {
1658 case LC_LOAD_WEAK_DYLIB
:
1659 attribute
= "weak_import";
1661 case LC_REEXPORT_DYLIB
:
1662 attribute
= "re-export";
1664 case LC_LOAD_UPWARD_DYLIB
:
1665 attribute
= "upward";
1667 case LC_LAZY_LOAD_DYLIB
:
1668 attribute
= "lazy_load";
1674 printf(" %-12s %s\n", attribute
, dylib
->name());
1678 template <typename A
>
1679 void DyldInfoPrinter
<A
>::printDRInfo()
1681 if ( fDRInfo
== NULL
) {
1682 printf("no Designated Requirements info\n");
1685 printf("dylibs DRs\n");
1686 const uint8_t* start
= ((uint8_t*)fHeader
+ fDRInfo
->dataoff());
1687 //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
1688 typedef Security::SuperBlob
<Security::kSecCodeMagicDRList
> DRListSuperBlob
;
1689 typedef Security::SuperBlob
<Security::kSecCodeMagicRequirementSet
> InternalRequirementsSetBlob
;
1690 const DRListSuperBlob
* topBlob
= (DRListSuperBlob
*)start
;
1691 if ( topBlob
->validateBlob(fDRInfo
->datasize()) ) {
1692 if ( topBlob
->count() == fDylibLoadCommands
.size() ) {
1693 for(unsigned i
=0; i
< topBlob
->count(); ++i
) {
1694 printf(" %-20s ", fDylibs
[i
]);
1695 const Security::BlobCore
* item
= topBlob
->find(i
);
1696 if ( item
!= NULL
) {
1697 const uint8_t* itemStart
= (uint8_t*)item
;
1698 const uint8_t* itemEnd
= itemStart
+ item
->length();
1699 for(const uint8_t* p
=itemStart
; p
< itemEnd
; ++p
)
1700 printf("%02X ", *p
);
1703 printf("no DR info");
1709 fprintf(stderr
, "superblob of DRs has a different number of elements than dylib load commands\n");
1713 fprintf(stderr
, "superblob of DRs invalid\n");
1722 template <typename A
>
1723 void DyldInfoPrinter
<A
>::printDataInCode()
1725 if ( fDataInCode
== NULL
) {
1726 printf("no data-in-code info\n");
1729 printf("offset length data-kind\n");
1730 const macho_data_in_code_entry
<P
>* start
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff());
1731 const macho_data_in_code_entry
<P
>* end
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff() + fDataInCode
->datasize());
1732 for (const macho_data_in_code_entry
<P
>* p
=start
; p
< end
; ++p
) {
1733 const char* kindStr
= "???";
1734 switch ( p
->kind() ) {
1739 kindStr
= "jumptable8";
1742 kindStr
= "jumptable16";
1745 kindStr
= "jumptable32";
1748 kindStr
= "jumptable32absolute";
1751 printf("0x%08X 0x%04X %s\n", p
->offset(), p
->length(), kindStr
);
1759 ppc::P::uint_t DyldInfoPrinter
<ppc
>::relocBase()
1761 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1762 return fFirstWritableSegment
->vmaddr();
1764 return fFirstSegment
->vmaddr();
1768 ppc64::P::uint_t DyldInfoPrinter
<ppc64
>::relocBase()
1770 if ( fWriteableSegmentWithAddrOver4G
)
1771 return fFirstWritableSegment
->vmaddr();
1773 return fFirstSegment
->vmaddr();
1777 x86::P::uint_t DyldInfoPrinter
<x86
>::relocBase()
1779 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1780 return fFirstWritableSegment
->vmaddr();
1782 return fFirstSegment
->vmaddr();
1786 x86_64::P::uint_t DyldInfoPrinter
<x86_64
>::relocBase()
1788 return fFirstWritableSegment
->vmaddr();
1791 #if SUPPORT_ARCH_arm_any
1793 arm::P::uint_t DyldInfoPrinter
<arm
>::relocBase()
1795 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1796 return fFirstWritableSegment
->vmaddr();
1798 return fFirstSegment
->vmaddr();
1802 #if SUPPORT_ARCH_arm64
1804 arm64::P::uint_t DyldInfoPrinter
<arm64
>::relocBase()
1806 return fFirstWritableSegment
->vmaddr();
1811 const char* DyldInfoPrinter
<ppc
>::relocTypeName(uint8_t r_type
)
1813 if ( r_type
== GENERIC_RELOC_VANILLA
)
1820 const char* DyldInfoPrinter
<ppc64
>::relocTypeName(uint8_t r_type
)
1822 if ( r_type
== GENERIC_RELOC_VANILLA
)
1829 const char* DyldInfoPrinter
<x86
>::relocTypeName(uint8_t r_type
)
1831 if ( r_type
== GENERIC_RELOC_VANILLA
)
1833 else if ( r_type
== GENERIC_RELOC_PB_LA_PTR
)
1834 return "pb pointer";
1840 const char* DyldInfoPrinter
<x86_64
>::relocTypeName(uint8_t r_type
)
1842 if ( r_type
== X86_64_RELOC_UNSIGNED
)
1848 #if SUPPORT_ARCH_arm_any
1850 const char* DyldInfoPrinter
<arm
>::relocTypeName(uint8_t r_type
)
1852 if ( r_type
== ARM_RELOC_VANILLA
)
1854 else if ( r_type
== ARM_RELOC_PB_LA_PTR
)
1855 return "pb pointer";
1861 #if SUPPORT_ARCH_arm64
1863 const char* DyldInfoPrinter
<arm64
>::relocTypeName(uint8_t r_type
)
1865 if ( r_type
== ARM64_RELOC_UNSIGNED
)
1871 template <typename A
>
1872 void DyldInfoPrinter
<A
>::printRelocRebaseInfo()
1874 if ( fDynamicSymbolTable
== NULL
) {
1875 printf("no classic dynamic symbol table");
1878 printf("rebase information (from local relocation records and indirect symbol table):\n");
1879 printf("segment section address type\n");
1880 // walk all local relocations
1881 pint_t rbase
= relocBase();
1882 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->locreloff());
1883 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nlocrel()];
1884 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1885 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
1886 pint_t addr
= reloc
->r_address() + rbase
;
1887 uint8_t segIndex
= segmentIndexForAddress(addr
);
1888 const char* typeName
= relocTypeName(reloc
->r_type());
1889 const char* segName
= segmentName(segIndex
);
1890 const char* sectName
= sectionName(segIndex
, addr
);
1891 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1894 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
1895 pint_t addr
= sreloc
->r_address() + rbase
;
1896 uint8_t segIndex
= segmentIndexForAddress(addr
);
1897 const char* typeName
= relocTypeName(sreloc
->r_type());
1898 const char* segName
= segmentName(segIndex
);
1899 const char* sectName
= sectionName(segIndex
, addr
);
1900 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1903 // look for local non-lazy-pointers
1904 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1905 uint8_t segIndex
= 0;
1906 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
, ++segIndex
) {
1907 const macho_segment_command
<P
>* segCmd
= *segit
;
1908 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1909 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1910 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1911 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1912 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
1913 uint32_t indirectOffset
= sect
->reserved1();
1914 uint32_t count
= sect
->size() / sizeof(pint_t
);
1915 for (uint32_t i
=0; i
< count
; ++i
) {
1916 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1917 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
1918 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1919 const char* typeName
= "pointer";
1920 const char* segName
= segmentName(segIndex
);
1921 const char* sectName
= sectionName(segIndex
, addr
);
1922 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1932 template <typename A
>
1933 void DyldInfoPrinter
<A
>::printSymbolTableExportInfo()
1935 if ( fDynamicSymbolTable
== NULL
) {
1936 printf("no classic dynamic symbol table");
1939 printf("export information (from symbol table):\n");
1940 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1941 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1942 const char* flags
= "";
1943 if ( sym
->n_desc() & N_WEAK_DEF
)
1944 flags
= "[weak_def] ";
1946 if ( sym
->n_desc() & N_ARM_THUMB_DEF
)
1948 printf("0x%08llX %s%s\n", sym
->n_value()+thumb
, flags
, &fStrings
[sym
->n_strx()]);
1953 template <typename A
>
1954 const char* DyldInfoPrinter
<A
>::symbolNameForAddress(uint64_t addr
)
1956 if ( fDynamicSymbolTable
!= NULL
) {
1957 // find exact match in globals
1958 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1959 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1960 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1961 return &fStrings
[sym
->n_strx()];
1964 // find exact match in local symbols
1965 const macho_nlist
<P
>* lastLocal
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1966 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()]; sym
< lastLocal
; ++sym
) {
1967 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1968 return &fStrings
[sym
->n_strx()];
1973 // find exact match in all symbols
1974 const macho_nlist
<P
>* lastSym
= &fSymbols
[fSymbolCount
];
1975 for (const macho_nlist
<P
>* sym
= &fSymbols
[0]; sym
< lastSym
; ++sym
) {
1976 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1977 return &fStrings
[sym
->n_strx()];
1985 template <typename A
>
1986 void DyldInfoPrinter
<A
>::printClassicBindingInfo()
1988 if ( fDynamicSymbolTable
== NULL
) {
1989 printf("no classic dynamic symbol table");
1992 printf("binding information (from relocations and indirect symbol table):\n");
1993 printf("segment section address type weak addend dylib symbol\n");
1994 // walk all external relocations
1995 pint_t rbase
= relocBase();
1996 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->extreloff());
1997 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1998 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1999 pint_t addr
= reloc
->r_address() + rbase
;
2000 uint32_t symbolIndex
= reloc
->r_symbolnum();
2001 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2002 const char* symbolName
= &fStrings
[sym
->n_strx()];
2003 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
2004 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2005 uint8_t segIndex
= segmentIndexForAddress(addr
);
2006 const char* typeName
= relocTypeName(reloc
->r_type());
2007 const char* segName
= segmentName(segIndex
);
2008 const char* sectName
= sectionName(segIndex
, addr
);
2009 const pint_t
* addressMapped
= mappedAddressForVMAddress(addr
);
2010 int64_t addend
= P::getP(*addressMapped
);
2011 if ( fHeader
->flags() & MH_PREBOUND
) {
2012 // In prebound binaries the content is already pointing to the target.
2013 // To get the addend requires subtracting out the base address it was prebound to.
2014 addend
-= sym
->n_value();
2016 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
2017 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
2019 // look for non-lazy pointers
2020 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2021 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2022 const macho_segment_command
<P
>* segCmd
= *segit
;
2023 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2024 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2025 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2026 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2027 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2028 uint32_t indirectOffset
= sect
->reserved1();
2029 uint32_t count
= sect
->size() / sizeof(pint_t
);
2030 for (uint32_t i
=0; i
< count
; ++i
) {
2031 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2032 if ( symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
2033 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2034 const char* symbolName
= &fStrings
[sym
->n_strx()];
2035 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
2036 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2037 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2038 uint8_t segIndex
= segmentIndexForAddress(addr
);
2039 const char* typeName
= "pointer";
2040 const char* segName
= segmentName(segIndex
);
2041 const char* sectName
= sectionName(segIndex
, addr
);
2043 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
2044 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
2054 template <typename A
>
2055 void DyldInfoPrinter
<A
>::printClassicLazyBindingInfo()
2057 if ( fDynamicSymbolTable
== NULL
) {
2058 printf("no classic dynamic symbol table");
2061 printf("lazy binding information (from section records and indirect symbol table):\n");
2062 printf("segment section address index dylib symbol\n");
2063 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2064 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2065 const macho_segment_command
<P
>* segCmd
= *segit
;
2066 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2067 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2068 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2069 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2070 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2071 uint32_t indirectOffset
= sect
->reserved1();
2072 uint32_t count
= sect
->size() / sizeof(pint_t
);
2073 for (uint32_t i
=0; i
< count
; ++i
) {
2074 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2075 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2076 const char* symbolName
= &fStrings
[sym
->n_strx()];
2077 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2078 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2079 uint8_t segIndex
= segmentIndexForAddress(addr
);
2080 const char* segName
= segmentName(segIndex
);
2081 const char* sectName
= sectionName(segIndex
, addr
);
2082 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2085 else if ( (type
== S_SYMBOL_STUBS
) && (((sect
->flags() & S_ATTR_SELF_MODIFYING_CODE
) != 0)) && (sect
->reserved2() == 5) ) {
2086 // i386 self-modifying stubs
2087 uint32_t indirectOffset
= sect
->reserved1();
2088 uint32_t count
= sect
->size() / 5;
2089 for (uint32_t i
=0; i
< count
; ++i
) {
2090 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2091 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
2092 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2093 const char* symbolName
= &fStrings
[sym
->n_strx()];
2094 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2095 pint_t addr
= sect
->addr() + i
*5;
2096 uint8_t segIndex
= segmentIndexForAddress(addr
);
2097 const char* segName
= segmentName(segIndex
);
2098 const char* sectName
= sectionName(segIndex
, addr
);
2099 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2108 static void dump(const char* path
)
2110 struct stat stat_buf
;
2113 int fd
= ::open(path
, O_RDONLY
, 0);
2115 throw "cannot open file";
2116 if ( ::fstat(fd
, &stat_buf
) != 0 )
2117 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
2118 uint32_t length
= stat_buf
.st_size
;
2119 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
2120 if ( p
== ((uint8_t*)(-1)) )
2121 throw "cannot map file";
2123 const mach_header
* mh
= (mach_header
*)p
;
2124 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2125 const struct fat_header
* fh
= (struct fat_header
*)p
;
2126 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
2127 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2128 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2129 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
2130 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
2131 cpu_type_t cpusubtype
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
);
2132 if ( ((cputype
== sPreferredArch
)
2133 && ((sPreferredSubArch
==0) || (sPreferredSubArch
==cpusubtype
)))
2134 || (sPreferredArch
== 0) ) {
2136 case CPU_TYPE_POWERPC
:
2137 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
2138 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2140 throw "in universal file, ppc slice does not contain ppc mach-o";
2143 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
2144 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2146 throw "in universal file, i386 slice does not contain i386 mach-o";
2148 case CPU_TYPE_POWERPC64
:
2149 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
2150 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2152 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
2154 case CPU_TYPE_X86_64
:
2155 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
2156 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2158 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
2160 #if SUPPORT_ARCH_arm_any
2162 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
2163 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2165 throw "in universal file, arm slice does not contain arm mach-o";
2168 #if SUPPORT_ARCH_arm64
2169 case CPU_TYPE_ARM64
:
2170 if ( DyldInfoPrinter
<arm64
>::validFile(p
+ offset
) )
2171 DyldInfoPrinter
<arm64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2173 throw "in universal file, arm64 slice does not contain arm mach-o";
2177 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
2182 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
2183 DyldInfoPrinter
<x86
>::make(p
, length
, path
, false);
2185 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
2186 DyldInfoPrinter
<ppc
>::make(p
, length
, path
, false);
2188 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
2189 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
, false);
2191 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
2192 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
, false);
2194 #if SUPPORT_ARCH_arm_any
2195 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
2196 DyldInfoPrinter
<arm
>::make(p
, length
, path
, false);
2199 #if SUPPORT_ARCH_arm64
2200 else if ( DyldInfoPrinter
<arm64
>::validFile(p
) ) {
2201 DyldInfoPrinter
<arm64
>::make(p
, length
, path
, false);
2205 throw "not a known file type";
2208 catch (const char* msg
) {
2209 throwf("%s in %s", msg
, path
);
2215 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
2216 "\t-dylibs print dependent dylibs\n"
2217 "\t-dr print dependent dylibs and show any recorded DR info\n"
2218 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
2219 "\t-bind print addresses dyld will set based on symbolic lookups\n"
2220 "\t-weak_bind print symbols which dyld must coalesce\n"
2221 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
2222 "\t-export print addresses of all symbols this file exports\n"
2223 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
2224 "\t-function_starts print table of function start addresses\n"
2225 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
2226 "\t-data_in_code print any data-in-code inforamtion\n"
2231 int main(int argc
, const char* argv
[])
2239 std::vector
<const char*> files
;
2240 for(int i
=1; i
< argc
; ++i
) {
2241 const char* arg
= argv
[i
];
2242 if ( arg
[0] == '-' ) {
2243 if ( strcmp(arg
, "-arch") == 0 ) {
2244 const char* arch
= ++i
<argc
? argv
[i
]: "";
2245 if ( strcmp(arch
, "ppc64") == 0 )
2246 sPreferredArch
= CPU_TYPE_POWERPC64
;
2247 else if ( strcmp(arch
, "ppc") == 0 )
2248 sPreferredArch
= CPU_TYPE_POWERPC
;
2249 else if ( strcmp(arch
, "i386") == 0 )
2250 sPreferredArch
= CPU_TYPE_I386
;
2251 else if ( strcmp(arch
, "x86_64") == 0 )
2252 sPreferredArch
= CPU_TYPE_X86_64
;
2253 #if SUPPORT_ARCH_arm64
2254 else if ( strcmp(arch
, "arm64") == 0 )
2255 sPreferredArch
= CPU_TYPE_ARM64
;
2259 throw "-arch missing architecture name";
2261 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
2262 if ( strcmp(t
->archName
,arch
) == 0 ) {
2263 sPreferredArch
= t
->cpuType
;
2265 sPreferredSubArch
= t
->cpuSubType
;
2271 throwf("unknown architecture %s", arch
);
2274 else if ( strcmp(arg
, "-rebase") == 0 ) {
2277 else if ( strcmp(arg
, "-bind") == 0 ) {
2280 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
2281 printWeakBind
= true;
2283 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
2284 printLazyBind
= true;
2286 else if ( strcmp(arg
, "-export") == 0 ) {
2289 else if ( strcmp(arg
, "-opcodes") == 0 ) {
2290 printOpcodes
= true;
2292 else if ( strcmp(arg
, "-export_dot") == 0 ) {
2293 printExportGraph
= true;
2295 else if ( strcmp(arg
, "-export_trie_nodes") == 0 ) {
2296 printExportNodes
= true;
2298 else if ( strcmp(arg
, "-shared_region") == 0 ) {
2299 printSharedRegion
= true;
2301 else if ( strcmp(arg
, "-function_starts") == 0 ) {
2302 printFunctionStarts
= true;
2304 else if ( strcmp(arg
, "-dylibs") == 0 ) {
2307 else if ( strcmp(arg
, "-dr") == 0 ) {
2310 else if ( strcmp(arg
, "-data_in_code") == 0 ) {
2311 printDataCode
= true;
2314 throwf("unknown option: %s\n", arg
);
2318 files
.push_back(arg
);
2321 if ( files
.size() == 0 )
2323 if ( files
.size() == 1 ) {
2327 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
2328 printf("\n%s:\n", *it
);
2333 catch (const char* msg
) {
2334 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);