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 template <typename A
>
256 DyldInfoPrinter
<A
>::DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
257 : fHeader(NULL
), fLength(fileLength
),
258 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fInfo(NULL
),
259 fSharedRegionInfo(NULL
), fFunctionStartsInfo(NULL
), fDataInCode(NULL
), fDRInfo(NULL
),
260 fBaseAddress(0), fDynamicSymbolTable(NULL
), fFirstSegment(NULL
), fFirstWritableSegment(NULL
),
261 fWriteableSegmentWithAddrOver4G(false)
264 if ( ! validFile(fileContent
) )
265 throw "not a mach-o file that can be checked";
267 fPath
= strdup(path
);
268 fHeader
= (const macho_header
<P
>*)fileContent
;
271 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
272 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
273 const uint32_t cmd_count
= fHeader
->ncmds();
274 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
275 const macho_load_command
<P
>* cmd
= cmds
;
276 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
277 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
278 if ( endOfCmd
> endOfLoadCommands
)
279 throwf("load command #%d extends beyond the end of the load commands", i
);
280 if ( endOfCmd
> endOfFile
)
281 throwf("load command #%d extends beyond the end of the file", i
);
282 switch ( cmd
->cmd() ) {
284 case LC_DYLD_INFO_ONLY
:
285 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
287 case macho_segment_command
<P
>::CMD
:
289 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
290 fSegments
.push_back(segCmd
);
291 if ( (segCmd
->fileoff() == 0) && (segCmd
->filesize() != 0) )
292 fBaseAddress
= segCmd
->vmaddr();
293 if ( fFirstSegment
== NULL
)
294 fFirstSegment
= segCmd
;
295 if ( (segCmd
->initprot() & VM_PROT_WRITE
) != 0 ) {
296 if ( fFirstWritableSegment
== NULL
)
297 fFirstWritableSegment
= segCmd
;
298 if ( segCmd
->vmaddr() > 0x100000000ULL
)
299 fWriteableSegmentWithAddrOver4G
= true;
304 case LC_LOAD_WEAK_DYLIB
:
305 case LC_REEXPORT_DYLIB
:
306 case LC_LOAD_UPWARD_DYLIB
:
307 case LC_LAZY_LOAD_DYLIB
:
309 const macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
310 fDylibLoadCommands
.push_back(dylib
);
311 const char* lastSlash
= strrchr(dylib
->name(), '/');
312 const char* leafName
= (lastSlash
!= NULL
) ? lastSlash
+1 : dylib
->name();
313 const char* firstDot
= strchr(leafName
, '.');
314 if ( firstDot
!= NULL
) {
315 char* t
= strdup(leafName
);
316 t
[firstDot
-leafName
] = '\0';
317 fDylibs
.push_back(t
);
320 fDylibs
.push_back(leafName
);
325 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
329 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
330 fSymbolCount
= symtab
->nsyms();
331 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
332 fStrings
= (char*)fHeader
+ symtab
->stroff();
333 fStringsEnd
= fStrings
+ symtab
->strsize();
336 case LC_SEGMENT_SPLIT_INFO
:
337 fSharedRegionInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
339 case LC_FUNCTION_STARTS
:
340 fFunctionStartsInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
342 case LC_DATA_IN_CODE
:
343 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
345 case LC_DYLIB_CODE_SIGN_DRS
:
346 fDRInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
349 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
353 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
354 if ( (cpu_type_t
)fHeader
->cputype() == t
->cpuType
) {
355 if ( t
->isSubType
&& ((cpu_subtype_t
)fHeader
->cpusubtype() != t
->cpuSubType
) )
357 printf("for arch %s:\n", t
->archName
);
366 printRelocRebaseInfo();
372 printClassicBindingInfo();
375 printWeakBindingInfo();
376 if ( printLazyBind
) {
378 printLazyBindingInfo();
380 printClassicLazyBindingInfo();
386 printSymbolTableExportInfo();
388 if ( printOpcodes
) {
389 printRebaseInfoOpcodes();
390 printBindingInfoOpcodes(false);
391 printBindingInfoOpcodes(true);
392 printLazyBindingOpcodes();
394 if ( printExportGraph
)
395 printExportInfoGraph();
396 if ( printExportNodes
)
397 printExportInfoNodes();
398 if ( printSharedRegion
)
399 printSharedRegionInfo();
400 if ( printFunctionStarts
)
401 printFunctionStartsInfo();
410 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
416 throwf("malformed uleb128");
418 uint64_t slice
= *p
& 0x7f;
420 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
421 throwf("uleb128 too big");
423 result
|= (slice
<< bit
);
431 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
438 throwf("malformed sleb128");
440 result
|= (((int64_t)(byte
& 0x7f)) << bit
);
442 } while (byte
& 0x80);
443 // sign extend negative numbers
444 if ( (byte
& 0x40) != 0 )
445 result
|= (-1LL) << bit
;
450 template <typename A
>
451 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
454 case REBASE_TYPE_POINTER
:
456 case REBASE_TYPE_TEXT_ABSOLUTE32
:
458 case REBASE_TYPE_TEXT_PCREL32
:
461 return "!!unknown!!";
465 template <typename A
>
466 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
469 case BIND_TYPE_POINTER
:
471 case BIND_TYPE_TEXT_ABSOLUTE32
:
473 case BIND_TYPE_TEXT_PCREL32
:
476 return "!!unknown!!";
480 template <typename A
>
481 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
483 if ( segIndex
> fSegments
.size() )
484 throw "segment index out of range";
485 return fSegments
[segIndex
]->vmaddr();
488 template <typename A
>
489 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
491 if ( segIndex
> fSegments
.size() )
492 throw "segment index out of range";
493 return fSegments
[segIndex
]->segname();
496 template <typename A
>
497 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
499 if ( segIndex
> fSegments
.size() )
500 throw "segment index out of range";
501 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
502 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
503 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
504 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
505 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
506 if ( strlen(sect
->sectname()) > 15 ) {
507 static char temp
[18];
508 strlcpy(temp
, sect
->sectname(), 17);
512 return sect
->sectname();
519 template <typename A
>
520 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
522 static char buffer
[64];
523 strcpy(buffer
, segmentName(segIndex
));
525 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
526 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
527 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
528 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
529 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
530 // section name may not be zero terminated
531 char* end
= &buffer
[strlen(buffer
)];
532 strlcpy(end
, sect
->sectname(), 16);
539 template <typename A
>
540 uint8_t DyldInfoPrinter
<A
>::segmentIndexForAddress(pint_t address
)
542 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
543 if ( (fSegments
[i
]->vmaddr() <= address
) && (address
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
547 throwf("address 0x%llX is not in any segment", (uint64_t)address
);
550 template <typename A
>
551 typename
A::P::uint_t
* DyldInfoPrinter
<A
>::mappedAddressForVMAddress(pint_t vmaddress
)
553 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
554 if ( (fSegments
[i
]->vmaddr() <= vmaddress
) && (vmaddress
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
555 unsigned long offsetInMappedFile
= fSegments
[i
]->fileoff()+vmaddress
-fSegments
[i
]->vmaddr();
556 return (pint_t
*)((uint8_t*)fHeader
+ offsetInMappedFile
);
559 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress
);
562 template <typename A
>
563 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
565 switch ( libraryOrdinal
) {
566 case BIND_SPECIAL_DYLIB_SELF
:
568 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
569 return "main-executable";
570 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
571 return "flat-namespace";
573 if ( libraryOrdinal
< BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
574 throw "unknown special ordinal";
575 if ( libraryOrdinal
> (int)fDylibs
.size() )
576 throw "libraryOrdinal out of range";
577 return fDylibs
[libraryOrdinal
-1];
580 template <typename A
>
581 const char* DyldInfoPrinter
<A
>::classicOrdinalName(int libraryOrdinal
)
583 if ( (fHeader
->flags() & MH_TWOLEVEL
) == 0 )
584 return "flat-namespace";
585 switch ( libraryOrdinal
) {
586 case SELF_LIBRARY_ORDINAL
:
588 case EXECUTABLE_ORDINAL
:
589 return "main-executable";
590 case DYNAMIC_LOOKUP_ORDINAL
:
591 return "flat-namespace";
593 if ( libraryOrdinal
> (int)fDylibs
.size() )
594 throw "libraryOrdinal out of range";
595 return fDylibs
[libraryOrdinal
-1];
598 template <typename A
>
599 void DyldInfoPrinter
<A
>::printRebaseInfo()
601 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
602 printf("no compressed rebase info\n");
605 printf("rebase information (from compressed dyld info):\n");
606 printf("segment section address type\n");
608 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
609 const uint8_t* end
= &p
[fInfo
->rebase_size()];
612 uint64_t segOffset
= 0;
616 pint_t segStartAddr
= 0;
617 const char* segName
= "??";
618 const char* typeName
= "??";
620 while ( !done
&& (p
< end
) ) {
621 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
622 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
625 case REBASE_OPCODE_DONE
:
628 case REBASE_OPCODE_SET_TYPE_IMM
:
630 typeName
= rebaseTypeName(type
);
632 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
633 segIndex
= immediate
;
634 segStartAddr
= segStartAddress(segIndex
);
635 segName
= segmentName(segIndex
);
636 segOffset
= read_uleb128(p
, end
);
638 case REBASE_OPCODE_ADD_ADDR_ULEB
:
639 segOffset
+= read_uleb128(p
, end
);
641 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
642 segOffset
+= immediate
*sizeof(pint_t
);
644 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
645 for (int i
=0; i
< immediate
; ++i
) {
646 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
647 segOffset
+= sizeof(pint_t
);
650 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
651 count
= read_uleb128(p
, end
);
652 for (uint32_t i
=0; i
< count
; ++i
) {
653 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
654 segOffset
+= sizeof(pint_t
);
657 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
658 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
659 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
661 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
662 count
= read_uleb128(p
, end
);
663 skip
= read_uleb128(p
, end
);
664 for (uint32_t i
=0; i
< count
; ++i
) {
665 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
666 segOffset
+= skip
+ sizeof(pint_t
);
670 throwf("bad rebase opcode %d", *p
);
679 template <typename A
>
680 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
682 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
683 printf("no compressed rebase info\n");
686 printf("rebase opcodes:\n");
687 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
688 const uint8_t* end
= &p
[fInfo
->rebase_size()];
691 uint64_t address
= fBaseAddress
;
694 unsigned int segmentIndex
;
696 while ( !done
&& (p
< end
) ) {
697 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
698 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
701 case REBASE_OPCODE_DONE
:
703 printf("REBASE_OPCODE_DONE()\n");
705 case REBASE_OPCODE_SET_TYPE_IMM
:
707 printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type
);
709 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
710 segmentIndex
= immediate
;
711 address
= read_uleb128(p
, end
);
712 printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex
, address
);
714 case REBASE_OPCODE_ADD_ADDR_ULEB
:
715 address
= read_uleb128(p
, end
);
716 printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address
);
718 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
719 address
= immediate
*sizeof(pint_t
);
720 printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address
);
722 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
723 printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate
);
725 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
726 count
= read_uleb128(p
, end
);
727 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count
);
729 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
730 skip
= read_uleb128(p
, end
) + sizeof(pint_t
);
731 printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip
);
733 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
734 count
= read_uleb128(p
, end
);
735 skip
= read_uleb128(p
, end
);
736 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count
, skip
);
739 throwf("bad rebase opcode %d", *p
);
751 template <typename A
>
752 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
754 if ( fInfo
== NULL
) {
755 printf("no compressed binding info\n");
757 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
758 printf("no compressed binding info\n");
760 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
761 printf("no compressed weak binding info\n");
764 const uint8_t* start
;
767 printf("weak binding opcodes:\n");
768 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
769 end
= &start
[fInfo
->weak_bind_size()];
772 printf("binding opcodes:\n");
773 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
774 end
= &start
[fInfo
->bind_size()];
776 const uint8_t* p
= start
;
779 uint64_t address
= fBaseAddress
;
780 const char* symbolName
= NULL
;
781 int libraryOrdinal
= 0;
783 uint32_t segmentIndex
= 0;
787 while ( !done
&& (p
< end
) ) {
788 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
789 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
790 uint32_t opcodeOffset
= p
-start
;
793 case BIND_OPCODE_DONE
:
795 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
797 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
798 libraryOrdinal
= immediate
;
799 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
801 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
802 libraryOrdinal
= read_uleb128(p
, end
);
803 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
805 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
806 // the special ordinals are negative numbers
807 if ( immediate
== 0 )
810 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
811 libraryOrdinal
= signExtended
;
813 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
815 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
817 symbolName
= (char*)p
;
821 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
823 case BIND_OPCODE_SET_TYPE_IMM
:
825 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
827 case BIND_OPCODE_SET_ADDEND_SLEB
:
828 addend
= read_sleb128(p
, end
);
829 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
831 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
832 segmentIndex
= immediate
;
833 address
= read_uleb128(p
, end
);
834 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
836 case BIND_OPCODE_ADD_ADDR_ULEB
:
837 skip
= read_uleb128(p
, end
);
838 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
840 case BIND_OPCODE_DO_BIND
:
841 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
843 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
844 skip
= read_uleb128(p
, end
);
845 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
847 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
848 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
849 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
851 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
852 count
= read_uleb128(p
, end
);
853 skip
= read_uleb128(p
, end
);
854 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
857 throwf("unknown bind opcode %d", *p
);
866 template <typename A
>
867 void DyldInfoPrinter
<A
>::printBindingInfo()
869 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
870 printf("no compressed binding info\n");
873 printf("bind information:\n");
874 printf("segment section address type addend dylib symbol\n");
875 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->bind_off();
876 const uint8_t* end
= &p
[fInfo
->bind_size()];
879 uint8_t segIndex
= 0;
880 uint64_t segOffset
= 0;
881 const char* symbolName
= NULL
;
882 const char* fromDylib
= "??";
883 int libraryOrdinal
= 0;
887 pint_t segStartAddr
= 0;
888 const char* segName
= "??";
889 const char* typeName
= "??";
890 const char* weak_import
= "";
892 while ( !done
&& (p
< end
) ) {
893 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
894 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
897 case BIND_OPCODE_DONE
:
900 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
901 libraryOrdinal
= immediate
;
902 fromDylib
= ordinalName(libraryOrdinal
);
904 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
905 libraryOrdinal
= read_uleb128(p
, end
);
906 fromDylib
= ordinalName(libraryOrdinal
);
908 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
909 // the special ordinals are negative numbers
910 if ( immediate
== 0 )
913 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
914 libraryOrdinal
= signExtended
;
916 fromDylib
= ordinalName(libraryOrdinal
);
918 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
919 symbolName
= (char*)p
;
923 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
924 weak_import
= " (weak import)";
928 case BIND_OPCODE_SET_TYPE_IMM
:
930 typeName
= bindTypeName(type
);
932 case BIND_OPCODE_SET_ADDEND_SLEB
:
933 addend
= read_sleb128(p
, end
);
935 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
936 segIndex
= immediate
;
937 segStartAddr
= segStartAddress(segIndex
);
938 segName
= segmentName(segIndex
);
939 segOffset
= read_uleb128(p
, end
);
941 case BIND_OPCODE_ADD_ADDR_ULEB
:
942 segOffset
+= read_uleb128(p
, end
);
944 case BIND_OPCODE_DO_BIND
:
945 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
946 segOffset
+= sizeof(pint_t
);
948 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
949 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
950 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
952 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
953 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
954 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
956 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
957 count
= read_uleb128(p
, end
);
958 skip
= read_uleb128(p
, end
);
959 for (uint32_t i
=0; i
< count
; ++i
) {
960 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
961 segOffset
+= skip
+ sizeof(pint_t
);
965 throwf("bad bind opcode %d", *p
);
972 template <typename A
>
973 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
975 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
976 printf("no weak binding\n");
979 printf("weak binding information:\n");
980 printf("segment section address type addend symbol\n");
981 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
982 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
985 uint8_t segIndex
= 0;
986 uint64_t segOffset
= 0;
987 const char* symbolName
= NULL
;
991 pint_t segStartAddr
= 0;
992 const char* segName
= "??";
993 const char* typeName
= "??";
995 while ( !done
&& (p
< end
) ) {
996 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
997 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1000 case BIND_OPCODE_DONE
:
1003 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1004 symbolName
= (char*)p
;
1008 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
1009 printf(" strong %s\n", symbolName
);
1011 case BIND_OPCODE_SET_TYPE_IMM
:
1013 typeName
= bindTypeName(type
);
1015 case BIND_OPCODE_SET_ADDEND_SLEB
:
1016 addend
= read_sleb128(p
, end
);
1018 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1019 segIndex
= immediate
;
1020 segStartAddr
= segStartAddress(segIndex
);
1021 segName
= segmentName(segIndex
);
1022 segOffset
= read_uleb128(p
, end
);
1024 case BIND_OPCODE_ADD_ADDR_ULEB
:
1025 segOffset
+= read_uleb128(p
, end
);
1027 case BIND_OPCODE_DO_BIND
:
1028 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1029 segOffset
+= sizeof(pint_t
);
1031 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1032 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1033 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1035 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1036 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1037 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1039 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1040 count
= read_uleb128(p
, end
);
1041 skip
= read_uleb128(p
, end
);
1042 for (uint32_t i
=0; i
< count
; ++i
) {
1043 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1044 segOffset
+= skip
+ sizeof(pint_t
);
1048 throwf("unknown weak bind opcode %d", *p
);
1056 template <typename A
>
1057 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
1059 if ( fInfo
== NULL
) {
1060 printf("no compressed dyld info\n");
1062 else if ( fInfo
->lazy_bind_off() == 0 ) {
1063 printf("no compressed lazy binding info\n");
1066 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1067 printf("segment section address index dylib symbol\n");
1068 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1069 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1071 uint8_t type
= BIND_TYPE_POINTER
;
1072 uint8_t segIndex
= 0;
1073 uint64_t segOffset
= 0;
1074 const char* symbolName
= NULL
;
1075 const char* fromDylib
= "??";
1076 int libraryOrdinal
= 0;
1078 uint32_t lazy_offset
= 0;
1079 pint_t segStartAddr
= 0;
1080 const char* segName
= "??";
1081 const char* typeName
= "??";
1082 const char* weak_import
= "";
1083 for (const uint8_t* p
=start
; p
< end
; ) {
1084 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1085 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1088 case BIND_OPCODE_DONE
:
1089 lazy_offset
= p
-start
;
1091 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1092 libraryOrdinal
= immediate
;
1093 fromDylib
= ordinalName(libraryOrdinal
);
1095 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1096 libraryOrdinal
= read_uleb128(p
, end
);
1097 fromDylib
= ordinalName(libraryOrdinal
);
1099 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1100 // the special ordinals are negative numbers
1101 if ( immediate
== 0 )
1104 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1105 libraryOrdinal
= signExtended
;
1107 fromDylib
= ordinalName(libraryOrdinal
);
1109 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1110 symbolName
= (char*)p
;
1114 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
1115 weak_import
= " (weak import)";
1119 case BIND_OPCODE_SET_TYPE_IMM
:
1121 typeName
= bindTypeName(type
);
1123 case BIND_OPCODE_SET_ADDEND_SLEB
:
1124 addend
= read_sleb128(p
, end
);
1126 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1127 segIndex
= immediate
;
1128 segStartAddr
= segStartAddress(segIndex
);
1129 segName
= segmentName(segIndex
);
1130 segOffset
= read_uleb128(p
, end
);
1132 case BIND_OPCODE_ADD_ADDR_ULEB
:
1133 segOffset
+= read_uleb128(p
, end
);
1135 case BIND_OPCODE_DO_BIND
:
1136 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
, weak_import
);
1137 segOffset
+= sizeof(pint_t
);
1140 throwf("bad lazy bind opcode %d", *p
);
1147 template <typename A
>
1148 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1150 if ( fInfo
== NULL
) {
1151 printf("no compressed dyld info\n");
1153 else if ( fInfo
->lazy_bind_off() == 0 ) {
1154 printf("no compressed lazy binding info\n");
1157 printf("lazy binding opcodes:\n");
1158 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1159 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1160 uint8_t type
= BIND_TYPE_POINTER
;
1162 uint64_t address
= fBaseAddress
;
1163 const char* symbolName
= NULL
;
1164 int libraryOrdinal
= 0;
1166 uint32_t segmentIndex
= 0;
1169 for (const uint8_t* p
= start
; p
< end
; ) {
1170 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1171 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1172 uint32_t opcodeOffset
= p
-start
;
1175 case BIND_OPCODE_DONE
:
1176 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1178 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1179 libraryOrdinal
= immediate
;
1180 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1182 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1183 libraryOrdinal
= read_uleb128(p
, end
);
1184 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1186 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1187 // the special ordinals are negative numbers
1188 if ( immediate
== 0 )
1191 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1192 libraryOrdinal
= signExtended
;
1194 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1196 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1198 symbolName
= (char*)p
;
1202 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1204 case BIND_OPCODE_SET_TYPE_IMM
:
1206 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1208 case BIND_OPCODE_SET_ADDEND_SLEB
:
1209 addend
= read_sleb128(p
, end
);
1210 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1212 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1213 segmentIndex
= immediate
;
1214 address
= read_uleb128(p
, end
);
1215 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1217 case BIND_OPCODE_ADD_ADDR_ULEB
:
1218 skip
= read_uleb128(p
, end
);
1219 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1221 case BIND_OPCODE_DO_BIND
:
1222 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1224 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1225 skip
= read_uleb128(p
, end
);
1226 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1228 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1229 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1230 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1232 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1233 count
= read_uleb128(p
, end
);
1234 skip
= read_uleb128(p
, end
);
1235 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1238 throwf("unknown bind opcode %d", *p
);
1245 struct SortExportsByAddress
1247 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1249 return ( left
.address
< right
.address
);
1253 template <typename A
>
1254 void DyldInfoPrinter
<A
>::printExportInfo()
1256 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1257 printf("no compressed export info\n");
1260 printf("export information (from trie):\n");
1261 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1262 const uint8_t* end
= &start
[fInfo
->export_size()];
1263 std::vector
<mach_o::trie::Entry
> list
;
1264 parseTrie(start
, end
, list
);
1265 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1266 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1267 const bool reExport
= (it
->flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
);
1268 const bool weakDef
= (it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
);
1269 const bool threadLocal
= ((it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
);
1270 const bool resolver
= (it
->flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
);
1272 printf("[re-export] ");
1274 printf("0x%08llX ", fBaseAddress
+it
->address
);
1275 printf("%s", it
->name
);
1276 if ( weakDef
|| threadLocal
|| resolver
) {
1277 bool needComma
= false;
1283 if ( threadLocal
) {
1286 printf("per-thread");
1292 printf("resolver=0x%08llX", it
->other
);
1298 if ( it
->importName
[0] == '\0' )
1299 printf(" (from %s)", fDylibs
[it
->other
- 1]);
1301 printf(" (%s from %s)", it
->importName
, fDylibs
[it
->other
- 1]);
1309 template <typename A
>
1310 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1311 const uint8_t* parent
, const uint8_t* p
,
1312 char* cummulativeString
, int curStrOffset
)
1314 const uint8_t* const me
= p
;
1315 const uint8_t terminalSize
= read_uleb128(p
, end
);
1316 const uint8_t* children
= p
+ terminalSize
;
1317 if ( terminalSize
!= 0 ) {
1318 uint32_t flags
= read_uleb128(p
, end
);
1319 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1320 uint64_t ordinal
= read_uleb128(p
, end
);
1321 const char* importName
= (const char*)p
;
1325 if ( *importName
== '\0' )
1326 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, ordinal
);
1328 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, importName
, ordinal
);
1331 uint64_t address
= read_uleb128(p
, end
);
1332 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1333 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
1334 read_uleb128(p
, end
);
1338 printf("\tnode%03ld;\n", (long)(me
-start
));
1340 const uint8_t childrenCount
= *children
++;
1341 const uint8_t* s
= children
;
1342 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1343 const char* edgeName
= (char*)s
;
1345 while (*s
!= '\0') {
1346 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1349 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1350 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1351 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1352 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1356 template <typename A
>
1357 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1359 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1360 printf("no compressed export info\n");
1363 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1364 const uint8_t* end
= &p
[fInfo
->export_size()];
1365 char cummulativeString
[2000];
1366 printf("digraph {\n");
1367 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1372 template <typename A
>
1373 void DyldInfoPrinter
<A
>::gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
1374 const uint8_t* parent
, const uint8_t* p
,
1375 std::vector
<uint32_t>& nodeStarts
)
1377 nodeStarts
.push_back(p
-start
);
1378 const uint8_t terminalSize
= read_uleb128(p
, end
);
1379 const uint8_t* children
= p
+ terminalSize
;
1381 const uint8_t childrenCount
= *children
++;
1382 const uint8_t* s
= children
;
1383 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1384 // skip over edge string
1388 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1389 gatherNodeStarts(start
, end
, start
, start
+childNodeOffet
, nodeStarts
);
1394 template <typename A
>
1395 void DyldInfoPrinter
<A
>::printExportInfoNodes()
1397 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1398 printf("no compressed export info\n");
1401 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1402 const uint8_t* end
= &start
[fInfo
->export_size()];
1403 std::vector
<uint32_t> nodeStarts
;
1404 gatherNodeStarts(start
, end
, start
, start
, nodeStarts
);
1405 std::sort(nodeStarts
.begin(), nodeStarts
.end());
1406 for (std::vector
<uint32_t>::const_iterator it
=nodeStarts
.begin(); it
!= nodeStarts
.end(); ++it
) {
1407 printf("0x%04X: ", *it
);
1408 const uint8_t* p
= start
+ *it
;
1409 uint64_t exportInfoSize
= read_uleb128(p
, end
);
1410 if ( exportInfoSize
!= 0 ) {
1411 // print terminal info
1412 uint64_t flags
= read_uleb128(p
, end
);
1413 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1414 uint64_t ordinal
= read_uleb128(p
, end
);
1415 const char* importName
= (const char*)p
;
1419 if ( strlen(importName
) == 0 )
1420 printf("[flags=REEXPORT ordinal=%llu] ", ordinal
);
1422 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal
, importName
);
1424 else if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1425 uint64_t stub
= read_uleb128(p
, end
);
1426 uint64_t resolver
= read_uleb128(p
, end
);
1427 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub
, resolver
);
1430 uint64_t address
= read_uleb128(p
, end
);
1431 if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR
)
1432 printf("[addr=0x%06llX] ", address
);
1433 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1434 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address
);
1436 printf("[flags=0x%llX addr=0x%06llX] ", flags
, address
);
1439 // print child edges
1440 const uint8_t childrenCount
= *p
++;
1441 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1442 const char* edgeName
= (const char*)p
;
1446 uint32_t childNodeOffet
= read_uleb128(p
, end
);
1447 printf("%s->0x%04X", edgeName
, childNodeOffet
);
1448 if ( i
< (childrenCount
-1) )
1458 template <typename A
>
1459 const uint8_t* DyldInfoPrinter
<A
>::printSharedRegionInfoForEachULEB128Address(const uint8_t* p
, uint8_t kind
)
1461 const char* kindStr
= "??";
1464 kindStr
= "32-bit pointer";
1467 kindStr
= "64-bit pointer";
1470 kindStr
= "ppc hi16";
1473 kindStr
= "32-bit offset to IMPORT";
1476 kindStr
= "thumb2 movw";
1479 kindStr
= "ARM movw";
1482 kindStr
= "thumb2 movt low high 4 bits=0";
1485 kindStr
= "thumb2 movt low high 4 bits=1";
1488 kindStr
= "thumb2 movt low high 4 bits=2";
1491 kindStr
= "thumb2 movt low high 4 bits=3";
1494 kindStr
= "thumb2 movt low high 4 bits=4";
1497 kindStr
= "thumb2 movt low high 4 bits=5";
1500 kindStr
= "thumb2 movt low high 4 bits=6";
1503 kindStr
= "thumb2 movt low high 4 bits=7";
1506 kindStr
= "thumb2 movt low high 4 bits=8";
1509 kindStr
= "thumb2 movt low high 4 bits=9";
1512 kindStr
= "thumb2 movt low high 4 bits=0xA";
1515 kindStr
= "thumb2 movt low high 4 bits=0xB";
1518 kindStr
= "thumb2 movt low high 4 bits=0xC";
1521 kindStr
= "thumb2 movt low high 4 bits=0xD";
1524 kindStr
= "thumb2 movt low high 4 bits=0xE";
1527 kindStr
= "thumb2 movt low high 4 bits=0xF";
1530 uint64_t address
= 0;
1535 uint8_t byte
= *p
++;
1536 delta
|= ((byte
& 0x7F) << shift
);
1538 if ( byte
< 0x80 ) {
1541 printf("0x%0llX %s\n", address
+fBaseAddress
, kindStr
);
1553 template <typename A
>
1554 void DyldInfoPrinter
<A
>::printSharedRegionInfo()
1556 if ( (fSharedRegionInfo
== NULL
) || (fSharedRegionInfo
->datasize() == 0) ) {
1557 printf("no shared region info\n");
1560 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fSharedRegionInfo
->dataoff();
1561 const uint8_t* infoEnd
= &infoStart
[fSharedRegionInfo
->datasize()];
1562 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
);) {
1563 uint8_t kind
= *p
++;
1564 p
= this->printSharedRegionInfoForEachULEB128Address(p
, kind
);
1570 #if SUPPORT_ARCH_arm_any
1572 void DyldInfoPrinter
<arm
>::printFunctionStartLine(uint64_t addr
)
1575 printf("0x%0llX [thumb] %s\n", (addr
& -2), symbolNameForAddress(addr
& -2));
1577 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1581 template <typename A
>
1582 void DyldInfoPrinter
<A
>::printFunctionStartLine(uint64_t addr
)
1584 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1588 template <typename A
>
1589 void DyldInfoPrinter
<A
>::printFunctionStartsInfo()
1591 if ( (fFunctionStartsInfo
== NULL
) || (fFunctionStartsInfo
->datasize() == 0) ) {
1592 printf("no function starts info\n");
1595 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fFunctionStartsInfo
->dataoff();
1596 const uint8_t* infoEnd
= &infoStart
[fFunctionStartsInfo
->datasize()];
1597 uint64_t address
= fBaseAddress
;
1598 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
); ) {
1603 uint8_t byte
= *p
++;
1604 delta
|= ((byte
& 0x7F) << shift
);
1606 if ( byte
< 0x80 ) {
1608 printFunctionStartLine(address
);
1616 template <typename A
>
1617 void DyldInfoPrinter
<A
>::printDylibsInfo()
1619 printf("attributes dependent dylibs\n");
1620 for(typename
std::vector
<const macho_dylib_command
<P
>*>::iterator it
= fDylibLoadCommands
.begin(); it
!= fDylibLoadCommands
.end(); ++it
) {
1621 const macho_dylib_command
<P
>* dylib
= *it
;
1622 const char* attribute
= "";
1623 switch ( dylib
->cmd() ) {
1624 case LC_LOAD_WEAK_DYLIB
:
1625 attribute
= "weak_import";
1627 case LC_REEXPORT_DYLIB
:
1628 attribute
= "re-export";
1630 case LC_LOAD_UPWARD_DYLIB
:
1631 attribute
= "upward";
1633 case LC_LAZY_LOAD_DYLIB
:
1634 attribute
= "lazy_load";
1640 printf(" %-12s %s\n", attribute
, dylib
->name());
1644 template <typename A
>
1645 void DyldInfoPrinter
<A
>::printDRInfo()
1647 if ( fDRInfo
== NULL
) {
1648 printf("no Designated Requirements info\n");
1651 printf("dylibs DRs\n");
1652 const uint8_t* start
= ((uint8_t*)fHeader
+ fDRInfo
->dataoff());
1653 //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
1654 typedef Security::SuperBlob
<Security::kSecCodeMagicDRList
> DRListSuperBlob
;
1655 typedef Security::SuperBlob
<Security::kSecCodeMagicRequirementSet
> InternalRequirementsSetBlob
;
1656 const DRListSuperBlob
* topBlob
= (DRListSuperBlob
*)start
;
1657 if ( topBlob
->validateBlob(fDRInfo
->datasize()) ) {
1658 if ( topBlob
->count() == fDylibLoadCommands
.size() ) {
1659 for(unsigned i
=0; i
< topBlob
->count(); ++i
) {
1660 printf(" %-20s ", fDylibs
[i
]);
1661 const Security::BlobCore
* item
= topBlob
->find(i
);
1662 if ( item
!= NULL
) {
1663 const uint8_t* itemStart
= (uint8_t*)item
;
1664 const uint8_t* itemEnd
= itemStart
+ item
->length();
1665 for(const uint8_t* p
=itemStart
; p
< itemEnd
; ++p
)
1666 printf("%02X ", *p
);
1669 printf("no DR info");
1675 fprintf(stderr
, "superblob of DRs has a different number of elements than dylib load commands\n");
1679 fprintf(stderr
, "superblob of DRs invalid\n");
1688 template <typename A
>
1689 void DyldInfoPrinter
<A
>::printDataInCode()
1691 if ( fDataInCode
== NULL
) {
1692 printf("no data-in-code info\n");
1695 printf("offset length data-kind\n");
1696 const macho_data_in_code_entry
<P
>* start
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff());
1697 const macho_data_in_code_entry
<P
>* end
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff() + fDataInCode
->datasize());
1698 for (const macho_data_in_code_entry
<P
>* p
=start
; p
< end
; ++p
) {
1699 const char* kindStr
= "???";
1700 switch ( p
->kind() ) {
1705 kindStr
= "jumptable8";
1708 kindStr
= "jumptable16";
1711 kindStr
= "jumptable32";
1714 kindStr
= "jumptable32absolute";
1717 printf("0x%08X 0x%04X %s\n", p
->offset(), p
->length(), kindStr
);
1725 ppc::P::uint_t DyldInfoPrinter
<ppc
>::relocBase()
1727 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1728 return fFirstWritableSegment
->vmaddr();
1730 return fFirstSegment
->vmaddr();
1734 ppc64::P::uint_t DyldInfoPrinter
<ppc64
>::relocBase()
1736 if ( fWriteableSegmentWithAddrOver4G
)
1737 return fFirstWritableSegment
->vmaddr();
1739 return fFirstSegment
->vmaddr();
1743 x86::P::uint_t DyldInfoPrinter
<x86
>::relocBase()
1745 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1746 return fFirstWritableSegment
->vmaddr();
1748 return fFirstSegment
->vmaddr();
1752 x86_64::P::uint_t DyldInfoPrinter
<x86_64
>::relocBase()
1754 // check for split-seg
1755 return fFirstWritableSegment
->vmaddr();
1758 #if SUPPORT_ARCH_arm_any
1760 arm::P::uint_t DyldInfoPrinter
<arm
>::relocBase()
1762 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1763 return fFirstWritableSegment
->vmaddr();
1765 return fFirstSegment
->vmaddr();
1771 const char* DyldInfoPrinter
<ppc
>::relocTypeName(uint8_t r_type
)
1773 if ( r_type
== GENERIC_RELOC_VANILLA
)
1780 const char* DyldInfoPrinter
<ppc64
>::relocTypeName(uint8_t r_type
)
1782 if ( r_type
== GENERIC_RELOC_VANILLA
)
1789 const char* DyldInfoPrinter
<x86
>::relocTypeName(uint8_t r_type
)
1791 if ( r_type
== GENERIC_RELOC_VANILLA
)
1793 else if ( r_type
== GENERIC_RELOC_PB_LA_PTR
)
1794 return "pb pointer";
1800 const char* DyldInfoPrinter
<x86_64
>::relocTypeName(uint8_t r_type
)
1802 if ( r_type
== X86_64_RELOC_UNSIGNED
)
1808 #if SUPPORT_ARCH_arm_any
1810 const char* DyldInfoPrinter
<arm
>::relocTypeName(uint8_t r_type
)
1812 if ( r_type
== ARM_RELOC_VANILLA
)
1814 else if ( r_type
== ARM_RELOC_PB_LA_PTR
)
1815 return "pb pointer";
1821 template <typename A
>
1822 void DyldInfoPrinter
<A
>::printRelocRebaseInfo()
1824 if ( fDynamicSymbolTable
== NULL
) {
1825 printf("no classic dynamic symbol table");
1828 printf("rebase information (from local relocation records and indirect symbol table):\n");
1829 printf("segment section address type\n");
1830 // walk all local relocations
1831 pint_t rbase
= relocBase();
1832 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->locreloff());
1833 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nlocrel()];
1834 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1835 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
1836 pint_t addr
= reloc
->r_address() + rbase
;
1837 uint8_t segIndex
= segmentIndexForAddress(addr
);
1838 const char* typeName
= relocTypeName(reloc
->r_type());
1839 const char* segName
= segmentName(segIndex
);
1840 const char* sectName
= sectionName(segIndex
, addr
);
1841 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1844 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
1845 pint_t addr
= sreloc
->r_address() + rbase
;
1846 uint8_t segIndex
= segmentIndexForAddress(addr
);
1847 const char* typeName
= relocTypeName(sreloc
->r_type());
1848 const char* segName
= segmentName(segIndex
);
1849 const char* sectName
= sectionName(segIndex
, addr
);
1850 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1853 // look for local non-lazy-pointers
1854 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1855 uint8_t segIndex
= 0;
1856 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
, ++segIndex
) {
1857 const macho_segment_command
<P
>* segCmd
= *segit
;
1858 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1859 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1860 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1861 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1862 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
1863 uint32_t indirectOffset
= sect
->reserved1();
1864 uint32_t count
= sect
->size() / sizeof(pint_t
);
1865 for (uint32_t i
=0; i
< count
; ++i
) {
1866 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1867 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
1868 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1869 const char* typeName
= "pointer";
1870 const char* segName
= segmentName(segIndex
);
1871 const char* sectName
= sectionName(segIndex
, addr
);
1872 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1882 template <typename A
>
1883 void DyldInfoPrinter
<A
>::printSymbolTableExportInfo()
1885 if ( fDynamicSymbolTable
== NULL
) {
1886 printf("no classic dynamic symbol table");
1889 printf("export information (from symbol table):\n");
1890 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1891 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1892 const char* flags
= "";
1893 if ( sym
->n_desc() & N_WEAK_DEF
)
1894 flags
= "[weak_def] ";
1896 if ( sym
->n_desc() & N_ARM_THUMB_DEF
)
1898 printf("0x%08llX %s%s\n", sym
->n_value()+thumb
, flags
, &fStrings
[sym
->n_strx()]);
1903 template <typename A
>
1904 const char* DyldInfoPrinter
<A
>::symbolNameForAddress(uint64_t addr
)
1906 if ( fDynamicSymbolTable
!= NULL
) {
1907 // find exact match in globals
1908 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1909 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1910 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1911 return &fStrings
[sym
->n_strx()];
1914 // find exact match in local symbols
1915 const macho_nlist
<P
>* lastLocal
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1916 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()]; sym
< lastLocal
; ++sym
) {
1917 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1918 return &fStrings
[sym
->n_strx()];
1923 // find exact match in all symbols
1924 const macho_nlist
<P
>* lastSym
= &fSymbols
[fSymbolCount
];
1925 for (const macho_nlist
<P
>* sym
= &fSymbols
[0]; sym
< lastSym
; ++sym
) {
1926 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1927 return &fStrings
[sym
->n_strx()];
1935 template <typename A
>
1936 void DyldInfoPrinter
<A
>::printClassicBindingInfo()
1938 if ( fDynamicSymbolTable
== NULL
) {
1939 printf("no classic dynamic symbol table");
1942 printf("binding information (from relocations and indirect symbol table):\n");
1943 printf("segment section address type weak addend dylib symbol\n");
1944 // walk all external relocations
1945 pint_t rbase
= relocBase();
1946 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->extreloff());
1947 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1948 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1949 pint_t addr
= reloc
->r_address() + rbase
;
1950 uint32_t symbolIndex
= reloc
->r_symbolnum();
1951 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1952 const char* symbolName
= &fStrings
[sym
->n_strx()];
1953 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
1954 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1955 uint8_t segIndex
= segmentIndexForAddress(addr
);
1956 const char* typeName
= relocTypeName(reloc
->r_type());
1957 const char* segName
= segmentName(segIndex
);
1958 const char* sectName
= sectionName(segIndex
, addr
);
1959 const pint_t
* addressMapped
= mappedAddressForVMAddress(addr
);
1960 int64_t addend
= P::getP(*addressMapped
);
1961 if ( fHeader
->flags() & MH_PREBOUND
) {
1962 // In prebound binaries the content is already pointing to the target.
1963 // To get the addend requires subtracting out the base address it was prebound to.
1964 addend
-= sym
->n_value();
1966 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1967 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
1969 // look for non-lazy pointers
1970 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1971 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
1972 const macho_segment_command
<P
>* segCmd
= *segit
;
1973 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1974 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1975 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1976 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1977 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
1978 uint32_t indirectOffset
= sect
->reserved1();
1979 uint32_t count
= sect
->size() / sizeof(pint_t
);
1980 for (uint32_t i
=0; i
< count
; ++i
) {
1981 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1982 if ( symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
1983 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1984 const char* symbolName
= &fStrings
[sym
->n_strx()];
1985 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
1986 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1987 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1988 uint8_t segIndex
= segmentIndexForAddress(addr
);
1989 const char* typeName
= "pointer";
1990 const char* segName
= segmentName(segIndex
);
1991 const char* sectName
= sectionName(segIndex
, addr
);
1993 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1994 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
2004 template <typename A
>
2005 void DyldInfoPrinter
<A
>::printClassicLazyBindingInfo()
2007 if ( fDynamicSymbolTable
== NULL
) {
2008 printf("no classic dynamic symbol table");
2011 printf("lazy binding information (from section records and indirect symbol table):\n");
2012 printf("segment section address index dylib symbol\n");
2013 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2014 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2015 const macho_segment_command
<P
>* segCmd
= *segit
;
2016 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2017 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2018 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2019 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2020 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2021 uint32_t indirectOffset
= sect
->reserved1();
2022 uint32_t count
= sect
->size() / sizeof(pint_t
);
2023 for (uint32_t i
=0; i
< count
; ++i
) {
2024 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2025 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2026 const char* symbolName
= &fStrings
[sym
->n_strx()];
2027 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2028 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2029 uint8_t segIndex
= segmentIndexForAddress(addr
);
2030 const char* segName
= segmentName(segIndex
);
2031 const char* sectName
= sectionName(segIndex
, addr
);
2032 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2035 else if ( (type
== S_SYMBOL_STUBS
) && (((sect
->flags() & S_ATTR_SELF_MODIFYING_CODE
) != 0)) && (sect
->reserved2() == 5) ) {
2036 // i386 self-modifying stubs
2037 uint32_t indirectOffset
= sect
->reserved1();
2038 uint32_t count
= sect
->size() / 5;
2039 for (uint32_t i
=0; i
< count
; ++i
) {
2040 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2041 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
2042 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2043 const char* symbolName
= &fStrings
[sym
->n_strx()];
2044 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2045 pint_t addr
= sect
->addr() + i
*5;
2046 uint8_t segIndex
= segmentIndexForAddress(addr
);
2047 const char* segName
= segmentName(segIndex
);
2048 const char* sectName
= sectionName(segIndex
, addr
);
2049 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2058 static void dump(const char* path
)
2060 struct stat stat_buf
;
2063 int fd
= ::open(path
, O_RDONLY
, 0);
2065 throw "cannot open file";
2066 if ( ::fstat(fd
, &stat_buf
) != 0 )
2067 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
2068 uint32_t length
= stat_buf
.st_size
;
2069 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
2070 if ( p
== ((uint8_t*)(-1)) )
2071 throw "cannot map file";
2073 const mach_header
* mh
= (mach_header
*)p
;
2074 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2075 const struct fat_header
* fh
= (struct fat_header
*)p
;
2076 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
2077 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2078 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2079 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
2080 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
2081 cpu_type_t cpusubtype
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
);
2082 if ( ((cputype
== sPreferredArch
)
2083 && ((sPreferredSubArch
==0) || (sPreferredSubArch
==cpusubtype
)))
2084 || (sPreferredArch
== 0) ) {
2086 case CPU_TYPE_POWERPC
:
2087 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
2088 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2090 throw "in universal file, ppc slice does not contain ppc mach-o";
2093 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
2094 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2096 throw "in universal file, i386 slice does not contain i386 mach-o";
2098 case CPU_TYPE_POWERPC64
:
2099 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
2100 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2102 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
2104 case CPU_TYPE_X86_64
:
2105 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
2106 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2108 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
2110 #if SUPPORT_ARCH_arm_any
2112 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
2113 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2115 throw "in universal file, arm slice does not contain arm mach-o";
2119 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
2124 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
2125 DyldInfoPrinter
<x86
>::make(p
, length
, path
, false);
2127 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
2128 DyldInfoPrinter
<ppc
>::make(p
, length
, path
, false);
2130 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
2131 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
, false);
2133 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
2134 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
, false);
2136 #if SUPPORT_ARCH_arm_any
2137 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
2138 DyldInfoPrinter
<arm
>::make(p
, length
, path
, false);
2142 throw "not a known file type";
2145 catch (const char* msg
) {
2146 throwf("%s in %s", msg
, path
);
2152 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
2153 "\t-dylibs print dependent dylibs\n"
2154 "\t-dr print dependent dylibs and show any recorded DR info\n"
2155 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
2156 "\t-bind print addresses dyld will set based on symbolic lookups\n"
2157 "\t-weak_bind print symbols which dyld must coalesce\n"
2158 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
2159 "\t-export print addresses of all symbols this file exports\n"
2160 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
2161 "\t-function_starts print table of function start addresses\n"
2162 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
2163 "\t-data_in_code print any data-in-code inforamtion\n"
2168 int main(int argc
, const char* argv
[])
2176 std::vector
<const char*> files
;
2177 for(int i
=1; i
< argc
; ++i
) {
2178 const char* arg
= argv
[i
];
2179 if ( arg
[0] == '-' ) {
2180 if ( strcmp(arg
, "-arch") == 0 ) {
2181 const char* arch
= ++i
<argc
? argv
[i
]: "";
2182 if ( strcmp(arch
, "ppc64") == 0 )
2183 sPreferredArch
= CPU_TYPE_POWERPC64
;
2184 else if ( strcmp(arch
, "ppc") == 0 )
2185 sPreferredArch
= CPU_TYPE_POWERPC
;
2186 else if ( strcmp(arch
, "i386") == 0 )
2187 sPreferredArch
= CPU_TYPE_I386
;
2188 else if ( strcmp(arch
, "x86_64") == 0 )
2189 sPreferredArch
= CPU_TYPE_X86_64
;
2192 throw "-arch missing architecture name";
2194 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
2195 if ( strcmp(t
->archName
,arch
) == 0 ) {
2196 sPreferredArch
= t
->cpuType
;
2198 sPreferredSubArch
= t
->cpuSubType
;
2204 throwf("unknown architecture %s", arch
);
2207 else if ( strcmp(arg
, "-rebase") == 0 ) {
2210 else if ( strcmp(arg
, "-bind") == 0 ) {
2213 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
2214 printWeakBind
= true;
2216 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
2217 printLazyBind
= true;
2219 else if ( strcmp(arg
, "-export") == 0 ) {
2222 else if ( strcmp(arg
, "-opcodes") == 0 ) {
2223 printOpcodes
= true;
2225 else if ( strcmp(arg
, "-export_dot") == 0 ) {
2226 printExportGraph
= true;
2228 else if ( strcmp(arg
, "-export_trie_nodes") == 0 ) {
2229 printExportNodes
= true;
2231 else if ( strcmp(arg
, "-shared_region") == 0 ) {
2232 printSharedRegion
= true;
2234 else if ( strcmp(arg
, "-function_starts") == 0 ) {
2235 printFunctionStarts
= true;
2237 else if ( strcmp(arg
, "-dylibs") == 0 ) {
2240 else if ( strcmp(arg
, "-dr") == 0 ) {
2243 else if ( strcmp(arg
, "-data_in_code") == 0 ) {
2244 printDataCode
= true;
2247 throwf("unknown option: %s\n", arg
);
2251 files
.push_back(arg
);
2254 if ( files
.size() == 0 )
2256 if ( files
.size() == 1 ) {
2260 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
2261 printf("\n%s:\n", *it
);
2266 catch (const char* msg
) {
2267 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);