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 <ext/hash_set>
38 #include "MachOFileAbstraction.hpp"
39 #include "Architectures.hpp"
40 #include "MachOTrie.hpp"
41 #include "../ld/code-sign-blobs/superblob.h"
43 static bool printRebase
= false;
44 static bool printBind
= false;
45 static bool printWeakBind
= false;
46 static bool printLazyBind
= false;
47 static bool printOpcodes
= false;
48 static bool printExport
= false;
49 static bool printExportGraph
= false;
50 static bool printExportNodes
= false;
51 static bool printSharedRegion
= false;
52 static bool printFunctionStarts
= false;
53 static bool printDylibs
= false;
54 static bool printDRs
= false;
55 static bool printDataCode
= false;
56 static cpu_type_t sPreferredArch
= 0;
57 static cpu_type_t sPreferredSubArch
= 0;
60 __attribute__((noreturn
))
61 static void throwf(const char* format
, ...)
65 va_start(list
, format
);
66 vasprintf(&p
, format
, list
);
78 static bool validFile(const uint8_t* fileContent
);
79 static DyldInfoPrinter
<A
>* make(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
80 { return new DyldInfoPrinter
<A
>(fileContent
, fileLength
, path
, printArch
); }
81 virtual ~DyldInfoPrinter() {}
85 typedef typename
A::P P
;
86 typedef typename
A::P::E E
;
87 typedef typename
A::P::uint_t pint_t
;
92 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
95 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> StringSet
;
97 DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
);
98 void printRebaseInfo();
99 void printRebaseInfoOpcodes();
100 void printBindingInfo();
101 void printWeakBindingInfo();
102 void printLazyBindingInfo();
103 void printBindingInfoOpcodes(bool weakBinding
);
104 void printWeakBindingInfoOpcodes();
105 void printLazyBindingOpcodes();
106 void printExportInfo();
107 void printExportInfoGraph();
108 void printExportInfoNodes();
109 void printRelocRebaseInfo();
110 void printSymbolTableExportInfo();
111 void printClassicLazyBindingInfo();
112 void printClassicBindingInfo();
113 void printSharedRegionInfo();
114 void printFunctionStartsInfo();
115 void printDylibsInfo();
117 void printDataInCode();
118 void printFunctionStartLine(uint64_t addr
);
119 const uint8_t* printSharedRegionInfoForEachULEB128Address(const uint8_t* p
, uint8_t kind
);
121 const char* relocTypeName(uint8_t r_type
);
122 uint8_t segmentIndexForAddress(pint_t addr
);
123 void processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
124 const uint8_t* parent
, const uint8_t* p
,
125 char* cummulativeString
, int curStrOffset
);
126 void gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
127 const uint8_t* parent
, const uint8_t* p
,
128 std::vector
<uint32_t>& nodeStarts
);
129 const char* rebaseTypeName(uint8_t type
);
130 const char* bindTypeName(uint8_t type
);
131 pint_t
segStartAddress(uint8_t segIndex
);
132 const char* segmentName(uint8_t segIndex
);
133 const char* sectionName(uint8_t segIndex
, pint_t address
);
134 const char* getSegAndSectName(uint8_t segIndex
, pint_t address
);
135 const char* ordinalName(int libraryOrdinal
);
136 const char* classicOrdinalName(int libraryOrdinal
);
137 pint_t
* mappedAddressForVMAddress(pint_t vmaddress
);
138 const char* symbolNameForAddress(uint64_t);
142 const macho_header
<P
>* fHeader
;
144 const char* fStrings
;
145 const char* fStringsEnd
;
146 const macho_nlist
<P
>* fSymbols
;
147 uint32_t fSymbolCount
;
148 const macho_dyld_info_command
<P
>* fInfo
;
149 const macho_linkedit_data_command
<P
>* fSharedRegionInfo
;
150 const macho_linkedit_data_command
<P
>* fFunctionStartsInfo
;
151 const macho_linkedit_data_command
<P
>* fDataInCode
;
152 const macho_linkedit_data_command
<P
>* fDRInfo
;
153 uint64_t fBaseAddress
;
154 const macho_dysymtab_command
<P
>* fDynamicSymbolTable
;
155 const macho_segment_command
<P
>* fFirstSegment
;
156 const macho_segment_command
<P
>* fFirstWritableSegment
;
157 bool fWriteableSegmentWithAddrOver4G
;
158 std::vector
<const macho_segment_command
<P
>*>fSegments
;
159 std::vector
<const char*> fDylibs
;
160 std::vector
<const macho_dylib_command
<P
>*> fDylibLoadCommands
;
166 bool DyldInfoPrinter
<ppc
>::validFile(const uint8_t* fileContent
)
168 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
169 if ( header
->magic() != MH_MAGIC
)
171 if ( header
->cputype() != CPU_TYPE_POWERPC
)
173 switch (header
->filetype()) {
185 bool DyldInfoPrinter
<ppc64
>::validFile(const uint8_t* fileContent
)
187 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
188 if ( header
->magic() != MH_MAGIC_64
)
190 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
192 switch (header
->filetype()) {
204 bool DyldInfoPrinter
<x86
>::validFile(const uint8_t* fileContent
)
206 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
207 if ( header
->magic() != MH_MAGIC
)
209 if ( header
->cputype() != CPU_TYPE_I386
)
211 switch (header
->filetype()) {
223 bool DyldInfoPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
225 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
226 if ( header
->magic() != MH_MAGIC_64
)
228 if ( header
->cputype() != CPU_TYPE_X86_64
)
230 switch (header
->filetype()) {
241 #if SUPPORT_ARCH_arm_any
243 bool DyldInfoPrinter
<arm
>::validFile(const uint8_t* fileContent
)
245 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
246 if ( header
->magic() != MH_MAGIC
)
248 if ( header
->cputype() != CPU_TYPE_ARM
)
250 switch (header
->filetype()) {
262 template <typename A
>
263 DyldInfoPrinter
<A
>::DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool printArch
)
264 : fHeader(NULL
), fLength(fileLength
),
265 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fInfo(NULL
),
266 fSharedRegionInfo(NULL
), fFunctionStartsInfo(NULL
), fDataInCode(NULL
), fDRInfo(NULL
),
267 fBaseAddress(0), fDynamicSymbolTable(NULL
), fFirstSegment(NULL
), fFirstWritableSegment(NULL
),
268 fWriteableSegmentWithAddrOver4G(false)
271 if ( ! validFile(fileContent
) )
272 throw "not a mach-o file that can be checked";
274 fPath
= strdup(path
);
275 fHeader
= (const macho_header
<P
>*)fileContent
;
278 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
279 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
280 const uint32_t cmd_count
= fHeader
->ncmds();
281 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
282 const macho_load_command
<P
>* cmd
= cmds
;
283 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
284 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
285 if ( endOfCmd
> endOfLoadCommands
)
286 throwf("load command #%d extends beyond the end of the load commands", i
);
287 if ( endOfCmd
> endOfFile
)
288 throwf("load command #%d extends beyond the end of the file", i
);
289 switch ( cmd
->cmd() ) {
291 case LC_DYLD_INFO_ONLY
:
292 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
294 case macho_segment_command
<P
>::CMD
:
296 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
297 fSegments
.push_back(segCmd
);
298 if ( (segCmd
->fileoff() == 0) && (segCmd
->filesize() != 0) )
299 fBaseAddress
= segCmd
->vmaddr();
300 if ( fFirstSegment
== NULL
)
301 fFirstSegment
= segCmd
;
302 if ( (segCmd
->initprot() & VM_PROT_WRITE
) != 0 ) {
303 if ( fFirstWritableSegment
== NULL
)
304 fFirstWritableSegment
= segCmd
;
305 if ( segCmd
->vmaddr() > 0x100000000ULL
)
306 fWriteableSegmentWithAddrOver4G
= true;
311 case LC_LOAD_WEAK_DYLIB
:
312 case LC_REEXPORT_DYLIB
:
313 case LC_LOAD_UPWARD_DYLIB
:
314 case LC_LAZY_LOAD_DYLIB
:
316 const macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
317 fDylibLoadCommands
.push_back(dylib
);
318 const char* lastSlash
= strrchr(dylib
->name(), '/');
319 const char* leafName
= (lastSlash
!= NULL
) ? lastSlash
+1 : dylib
->name();
320 const char* firstDot
= strchr(leafName
, '.');
321 if ( firstDot
!= NULL
) {
322 char* t
= strdup(leafName
);
323 t
[firstDot
-leafName
] = '\0';
324 fDylibs
.push_back(t
);
327 fDylibs
.push_back(leafName
);
332 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
336 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
337 fSymbolCount
= symtab
->nsyms();
338 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
339 fStrings
= (char*)fHeader
+ symtab
->stroff();
340 fStringsEnd
= fStrings
+ symtab
->strsize();
343 case LC_SEGMENT_SPLIT_INFO
:
344 fSharedRegionInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
346 case LC_FUNCTION_STARTS
:
347 fFunctionStartsInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
349 case LC_DATA_IN_CODE
:
350 fDataInCode
= (macho_linkedit_data_command
<P
>*)cmd
;
352 case LC_DYLIB_CODE_SIGN_DRS
:
353 fDRInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
356 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
360 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
361 if ( (cpu_type_t
)fHeader
->cputype() == t
->cpuType
) {
362 if ( t
->isSubType
&& ((cpu_subtype_t
)fHeader
->cpusubtype() != t
->cpuSubType
) )
364 printf("for arch %s:\n", t
->archName
);
373 printRelocRebaseInfo();
379 printClassicBindingInfo();
382 printWeakBindingInfo();
383 if ( printLazyBind
) {
385 printLazyBindingInfo();
387 printClassicLazyBindingInfo();
393 printSymbolTableExportInfo();
395 if ( printOpcodes
) {
396 printRebaseInfoOpcodes();
397 printBindingInfoOpcodes(false);
398 printBindingInfoOpcodes(true);
399 printLazyBindingOpcodes();
401 if ( printExportGraph
)
402 printExportInfoGraph();
403 if ( printExportNodes
)
404 printExportInfoNodes();
405 if ( printSharedRegion
)
406 printSharedRegionInfo();
407 if ( printFunctionStarts
)
408 printFunctionStartsInfo();
417 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
423 throwf("malformed uleb128");
425 uint64_t slice
= *p
& 0x7f;
427 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
428 throwf("uleb128 too big");
430 result
|= (slice
<< bit
);
438 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
445 throwf("malformed sleb128");
447 result
|= (((int64_t)(byte
& 0x7f)) << bit
);
449 } while (byte
& 0x80);
450 // sign extend negative numbers
451 if ( (byte
& 0x40) != 0 )
452 result
|= (-1LL) << bit
;
457 template <typename A
>
458 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
461 case REBASE_TYPE_POINTER
:
463 case REBASE_TYPE_TEXT_ABSOLUTE32
:
465 case REBASE_TYPE_TEXT_PCREL32
:
468 return "!!unknown!!";
472 template <typename A
>
473 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
476 case BIND_TYPE_POINTER
:
478 case BIND_TYPE_TEXT_ABSOLUTE32
:
480 case BIND_TYPE_TEXT_PCREL32
:
483 return "!!unknown!!";
487 template <typename A
>
488 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
490 if ( segIndex
> fSegments
.size() )
491 throw "segment index out of range";
492 return fSegments
[segIndex
]->vmaddr();
495 template <typename A
>
496 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
498 if ( segIndex
> fSegments
.size() )
499 throw "segment index out of range";
500 return fSegments
[segIndex
]->segname();
503 template <typename A
>
504 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
506 if ( segIndex
> fSegments
.size() )
507 throw "segment index out of range";
508 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
509 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
510 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
511 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
512 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
513 if ( strlen(sect
->sectname()) > 15 ) {
514 static char temp
[18];
515 strlcpy(temp
, sect
->sectname(), 17);
519 return sect
->sectname();
526 template <typename A
>
527 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
529 static char buffer
[64];
530 strcpy(buffer
, segmentName(segIndex
));
532 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
533 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
534 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
535 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
536 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
537 // section name may not be zero terminated
538 char* end
= &buffer
[strlen(buffer
)];
539 strlcpy(end
, sect
->sectname(), 16);
546 template <typename A
>
547 uint8_t DyldInfoPrinter
<A
>::segmentIndexForAddress(pint_t address
)
549 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
550 if ( (fSegments
[i
]->vmaddr() <= address
) && (address
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
554 throwf("address 0x%llX is not in any segment", (uint64_t)address
);
557 template <typename A
>
558 typename
A::P::uint_t
* DyldInfoPrinter
<A
>::mappedAddressForVMAddress(pint_t vmaddress
)
560 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
561 if ( (fSegments
[i
]->vmaddr() <= vmaddress
) && (vmaddress
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
562 unsigned long offsetInMappedFile
= fSegments
[i
]->fileoff()+vmaddress
-fSegments
[i
]->vmaddr();
563 return (pint_t
*)((uint8_t*)fHeader
+ offsetInMappedFile
);
566 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress
);
569 template <typename A
>
570 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
572 switch ( libraryOrdinal
) {
573 case BIND_SPECIAL_DYLIB_SELF
:
575 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
576 return "main-executable";
577 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
578 return "flat-namespace";
580 if ( libraryOrdinal
< BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
581 throw "unknown special ordinal";
582 if ( libraryOrdinal
> (int)fDylibs
.size() )
583 throw "libraryOrdinal out of range";
584 return fDylibs
[libraryOrdinal
-1];
587 template <typename A
>
588 const char* DyldInfoPrinter
<A
>::classicOrdinalName(int libraryOrdinal
)
590 if ( (fHeader
->flags() & MH_TWOLEVEL
) == 0 )
591 return "flat-namespace";
592 switch ( libraryOrdinal
) {
593 case SELF_LIBRARY_ORDINAL
:
595 case EXECUTABLE_ORDINAL
:
596 return "main-executable";
597 case DYNAMIC_LOOKUP_ORDINAL
:
598 return "flat-namespace";
600 if ( libraryOrdinal
> (int)fDylibs
.size() )
601 throw "libraryOrdinal out of range";
602 return fDylibs
[libraryOrdinal
-1];
605 template <typename A
>
606 void DyldInfoPrinter
<A
>::printRebaseInfo()
608 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
609 printf("no compressed rebase info\n");
612 printf("rebase information (from compressed dyld info):\n");
613 printf("segment section address type\n");
615 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
616 const uint8_t* end
= &p
[fInfo
->rebase_size()];
619 uint64_t segOffset
= 0;
623 pint_t segStartAddr
= 0;
624 const char* segName
= "??";
625 const char* typeName
= "??";
627 while ( !done
&& (p
< end
) ) {
628 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
629 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
632 case REBASE_OPCODE_DONE
:
635 case REBASE_OPCODE_SET_TYPE_IMM
:
637 typeName
= rebaseTypeName(type
);
639 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
640 segIndex
= immediate
;
641 segStartAddr
= segStartAddress(segIndex
);
642 segName
= segmentName(segIndex
);
643 segOffset
= read_uleb128(p
, end
);
645 case REBASE_OPCODE_ADD_ADDR_ULEB
:
646 segOffset
+= read_uleb128(p
, end
);
648 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
649 segOffset
+= immediate
*sizeof(pint_t
);
651 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
652 for (int i
=0; i
< immediate
; ++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_ULEB_TIMES
:
658 count
= read_uleb128(p
, end
);
659 for (uint32_t i
=0; i
< count
; ++i
) {
660 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
661 segOffset
+= sizeof(pint_t
);
664 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
665 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
666 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
668 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
669 count
= read_uleb128(p
, end
);
670 skip
= read_uleb128(p
, end
);
671 for (uint32_t i
=0; i
< count
; ++i
) {
672 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
673 segOffset
+= skip
+ sizeof(pint_t
);
677 throwf("bad rebase opcode %d", *p
);
686 template <typename A
>
687 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
689 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
690 printf("no compressed rebase info\n");
693 printf("rebase opcodes:\n");
694 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
695 const uint8_t* end
= &p
[fInfo
->rebase_size()];
698 uint64_t address
= fBaseAddress
;
701 unsigned int segmentIndex
;
703 while ( !done
&& (p
< end
) ) {
704 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
705 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
708 case REBASE_OPCODE_DONE
:
710 printf("REBASE_OPCODE_DONE()\n");
712 case REBASE_OPCODE_SET_TYPE_IMM
:
714 printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type
);
716 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
717 segmentIndex
= immediate
;
718 address
= read_uleb128(p
, end
);
719 printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex
, address
);
721 case REBASE_OPCODE_ADD_ADDR_ULEB
:
722 address
= read_uleb128(p
, end
);
723 printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address
);
725 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
726 address
= immediate
*sizeof(pint_t
);
727 printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address
);
729 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
730 printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate
);
732 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
733 count
= read_uleb128(p
, end
);
734 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count
);
736 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
737 skip
= read_uleb128(p
, end
) + sizeof(pint_t
);
738 printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip
);
740 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
741 count
= read_uleb128(p
, end
);
742 skip
= read_uleb128(p
, end
);
743 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count
, skip
);
746 throwf("bad rebase opcode %d", *p
);
758 template <typename A
>
759 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
761 if ( fInfo
== NULL
) {
762 printf("no compressed binding info\n");
764 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
765 printf("no compressed binding info\n");
767 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
768 printf("no compressed weak binding info\n");
771 const uint8_t* start
;
774 printf("weak binding opcodes:\n");
775 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
776 end
= &start
[fInfo
->weak_bind_size()];
779 printf("binding opcodes:\n");
780 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
781 end
= &start
[fInfo
->bind_size()];
783 const uint8_t* p
= start
;
786 uint64_t address
= fBaseAddress
;
787 const char* symbolName
= NULL
;
788 int libraryOrdinal
= 0;
790 uint32_t segmentIndex
= 0;
794 while ( !done
&& (p
< end
) ) {
795 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
796 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
797 uint32_t opcodeOffset
= p
-start
;
800 case BIND_OPCODE_DONE
:
802 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
804 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
805 libraryOrdinal
= immediate
;
806 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
808 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
809 libraryOrdinal
= read_uleb128(p
, end
);
810 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
812 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
813 // the special ordinals are negative numbers
814 if ( immediate
== 0 )
817 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
818 libraryOrdinal
= signExtended
;
820 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
822 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
824 symbolName
= (char*)p
;
828 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
830 case BIND_OPCODE_SET_TYPE_IMM
:
832 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
834 case BIND_OPCODE_SET_ADDEND_SLEB
:
835 addend
= read_sleb128(p
, end
);
836 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
838 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
839 segmentIndex
= immediate
;
840 address
= read_uleb128(p
, end
);
841 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
843 case BIND_OPCODE_ADD_ADDR_ULEB
:
844 skip
= read_uleb128(p
, end
);
845 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
847 case BIND_OPCODE_DO_BIND
:
848 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
850 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
851 skip
= read_uleb128(p
, end
);
852 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
854 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
855 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
856 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
858 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
859 count
= read_uleb128(p
, end
);
860 skip
= read_uleb128(p
, end
);
861 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
864 throwf("unknown bind opcode %d", *p
);
873 template <typename A
>
874 void DyldInfoPrinter
<A
>::printBindingInfo()
876 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
877 printf("no compressed binding info\n");
880 printf("bind information:\n");
881 printf("segment section address type addend dylib symbol\n");
882 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->bind_off();
883 const uint8_t* end
= &p
[fInfo
->bind_size()];
886 uint8_t segIndex
= 0;
887 uint64_t segOffset
= 0;
888 const char* symbolName
= NULL
;
889 const char* fromDylib
= "??";
890 int libraryOrdinal
= 0;
894 pint_t segStartAddr
= 0;
895 const char* segName
= "??";
896 const char* typeName
= "??";
897 const char* weak_import
= "";
899 while ( !done
&& (p
< end
) ) {
900 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
901 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
904 case BIND_OPCODE_DONE
:
907 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
908 libraryOrdinal
= immediate
;
909 fromDylib
= ordinalName(libraryOrdinal
);
911 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
912 libraryOrdinal
= read_uleb128(p
, end
);
913 fromDylib
= ordinalName(libraryOrdinal
);
915 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
916 // the special ordinals are negative numbers
917 if ( immediate
== 0 )
920 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
921 libraryOrdinal
= signExtended
;
923 fromDylib
= ordinalName(libraryOrdinal
);
925 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
926 symbolName
= (char*)p
;
930 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
931 weak_import
= " (weak import)";
935 case BIND_OPCODE_SET_TYPE_IMM
:
937 typeName
= bindTypeName(type
);
939 case BIND_OPCODE_SET_ADDEND_SLEB
:
940 addend
= read_sleb128(p
, end
);
942 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
943 segIndex
= immediate
;
944 segStartAddr
= segStartAddress(segIndex
);
945 segName
= segmentName(segIndex
);
946 segOffset
= read_uleb128(p
, end
);
948 case BIND_OPCODE_ADD_ADDR_ULEB
:
949 segOffset
+= read_uleb128(p
, end
);
951 case BIND_OPCODE_DO_BIND
:
952 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
953 segOffset
+= sizeof(pint_t
);
955 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
956 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
957 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
959 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
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
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
963 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
964 count
= read_uleb128(p
, end
);
965 skip
= read_uleb128(p
, end
);
966 for (uint32_t i
=0; i
< count
; ++i
) {
967 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
968 segOffset
+= skip
+ sizeof(pint_t
);
972 throwf("bad bind opcode %d", *p
);
979 template <typename A
>
980 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
982 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
983 printf("no weak binding\n");
986 printf("weak binding information:\n");
987 printf("segment section address type addend symbol\n");
988 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
989 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
992 uint8_t segIndex
= 0;
993 uint64_t segOffset
= 0;
994 const char* symbolName
= NULL
;
998 pint_t segStartAddr
= 0;
999 const char* segName
= "??";
1000 const char* typeName
= "??";
1002 while ( !done
&& (p
< end
) ) {
1003 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1004 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1007 case BIND_OPCODE_DONE
:
1010 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1011 symbolName
= (char*)p
;
1015 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
1016 printf(" strong %s\n", symbolName
);
1018 case BIND_OPCODE_SET_TYPE_IMM
:
1020 typeName
= bindTypeName(type
);
1022 case BIND_OPCODE_SET_ADDEND_SLEB
:
1023 addend
= read_sleb128(p
, end
);
1025 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1026 segIndex
= immediate
;
1027 segStartAddr
= segStartAddress(segIndex
);
1028 segName
= segmentName(segIndex
);
1029 segOffset
= read_uleb128(p
, end
);
1031 case BIND_OPCODE_ADD_ADDR_ULEB
:
1032 segOffset
+= read_uleb128(p
, end
);
1034 case BIND_OPCODE_DO_BIND
:
1035 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1036 segOffset
+= sizeof(pint_t
);
1038 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1039 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1040 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1042 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1043 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1044 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1046 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1047 count
= read_uleb128(p
, end
);
1048 skip
= read_uleb128(p
, end
);
1049 for (uint32_t i
=0; i
< count
; ++i
) {
1050 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1051 segOffset
+= skip
+ sizeof(pint_t
);
1055 throwf("unknown weak bind opcode %d", *p
);
1063 template <typename A
>
1064 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
1066 if ( fInfo
== NULL
) {
1067 printf("no compressed dyld info\n");
1069 else if ( fInfo
->lazy_bind_off() == 0 ) {
1070 printf("no compressed lazy binding info\n");
1073 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1074 printf("segment section address index dylib symbol\n");
1075 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1076 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1078 uint8_t type
= BIND_TYPE_POINTER
;
1079 uint8_t segIndex
= 0;
1080 uint64_t segOffset
= 0;
1081 const char* symbolName
= NULL
;
1082 const char* fromDylib
= "??";
1083 int libraryOrdinal
= 0;
1085 uint32_t lazy_offset
= 0;
1086 pint_t segStartAddr
= 0;
1087 const char* segName
= "??";
1088 const char* typeName
= "??";
1089 const char* weak_import
= "";
1090 for (const uint8_t* p
=start
; p
< end
; ) {
1091 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1092 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1095 case BIND_OPCODE_DONE
:
1096 lazy_offset
= p
-start
;
1098 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1099 libraryOrdinal
= immediate
;
1100 fromDylib
= ordinalName(libraryOrdinal
);
1102 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1103 libraryOrdinal
= read_uleb128(p
, end
);
1104 fromDylib
= ordinalName(libraryOrdinal
);
1106 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1107 // the special ordinals are negative numbers
1108 if ( immediate
== 0 )
1111 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1112 libraryOrdinal
= signExtended
;
1114 fromDylib
= ordinalName(libraryOrdinal
);
1116 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1117 symbolName
= (char*)p
;
1121 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
1122 weak_import
= " (weak import)";
1126 case BIND_OPCODE_SET_TYPE_IMM
:
1128 typeName
= bindTypeName(type
);
1130 case BIND_OPCODE_SET_ADDEND_SLEB
:
1131 addend
= read_sleb128(p
, end
);
1133 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1134 segIndex
= immediate
;
1135 segStartAddr
= segStartAddress(segIndex
);
1136 segName
= segmentName(segIndex
);
1137 segOffset
= read_uleb128(p
, end
);
1139 case BIND_OPCODE_ADD_ADDR_ULEB
:
1140 segOffset
+= read_uleb128(p
, end
);
1142 case BIND_OPCODE_DO_BIND
:
1143 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
, weak_import
);
1144 segOffset
+= sizeof(pint_t
);
1147 throwf("bad lazy bind opcode %d", *p
);
1154 template <typename A
>
1155 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1157 if ( fInfo
== NULL
) {
1158 printf("no compressed dyld info\n");
1160 else if ( fInfo
->lazy_bind_off() == 0 ) {
1161 printf("no compressed lazy binding info\n");
1164 printf("lazy binding opcodes:\n");
1165 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1166 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1167 uint8_t type
= BIND_TYPE_POINTER
;
1169 uint64_t address
= fBaseAddress
;
1170 const char* symbolName
= NULL
;
1171 int libraryOrdinal
= 0;
1173 uint32_t segmentIndex
= 0;
1176 for (const uint8_t* p
= start
; p
< end
; ) {
1177 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1178 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1179 uint32_t opcodeOffset
= p
-start
;
1182 case BIND_OPCODE_DONE
:
1183 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1185 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1186 libraryOrdinal
= immediate
;
1187 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1189 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1190 libraryOrdinal
= read_uleb128(p
, end
);
1191 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1193 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1194 // the special ordinals are negative numbers
1195 if ( immediate
== 0 )
1198 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1199 libraryOrdinal
= signExtended
;
1201 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1203 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1205 symbolName
= (char*)p
;
1209 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1211 case BIND_OPCODE_SET_TYPE_IMM
:
1213 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1215 case BIND_OPCODE_SET_ADDEND_SLEB
:
1216 addend
= read_sleb128(p
, end
);
1217 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1219 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1220 segmentIndex
= immediate
;
1221 address
= read_uleb128(p
, end
);
1222 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1224 case BIND_OPCODE_ADD_ADDR_ULEB
:
1225 skip
= read_uleb128(p
, end
);
1226 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1228 case BIND_OPCODE_DO_BIND
:
1229 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1231 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1232 skip
= read_uleb128(p
, end
);
1233 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1235 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1236 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1237 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1239 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1240 count
= read_uleb128(p
, end
);
1241 skip
= read_uleb128(p
, end
);
1242 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1245 throwf("unknown bind opcode %d", *p
);
1252 struct SortExportsByAddress
1254 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1256 return ( left
.address
< right
.address
);
1260 template <typename A
>
1261 void DyldInfoPrinter
<A
>::printExportInfo()
1263 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1264 printf("no compressed export info\n");
1267 printf("export information (from trie):\n");
1268 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1269 const uint8_t* end
= &start
[fInfo
->export_size()];
1270 std::vector
<mach_o::trie::Entry
> list
;
1271 parseTrie(start
, end
, list
);
1272 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1273 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1274 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1275 if ( it
->importName
[0] == '\0' )
1276 fprintf(stdout
, "[re-export] %s from dylib=%llu\n", it
->name
, it
->other
);
1278 fprintf(stdout
, "[re-export] %s from dylib=%llu named=%s\n", it
->name
, it
->other
, it
->importName
);
1281 const char* flags
= "";
1282 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
)
1283 flags
= "[weak_def] ";
1284 else if ( (it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1285 flags
= "[per-thread] ";
1286 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1287 flags
= "[resolver] ";
1288 fprintf(stdout
, "0x%08llX %s%s (resolver=0x%08llX)\n", fBaseAddress
+it
->address
, flags
, it
->name
, it
->other
);
1291 fprintf(stdout
, "0x%08llX %s%s\n", fBaseAddress
+it
->address
, flags
, it
->name
);
1299 template <typename A
>
1300 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1301 const uint8_t* parent
, const uint8_t* p
,
1302 char* cummulativeString
, int curStrOffset
)
1304 const uint8_t* const me
= p
;
1305 const uint8_t terminalSize
= read_uleb128(p
, end
);
1306 const uint8_t* children
= p
+ terminalSize
;
1307 if ( terminalSize
!= 0 ) {
1308 uint32_t flags
= read_uleb128(p
, end
);
1309 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1310 uint64_t ordinal
= read_uleb128(p
, end
);
1311 const char* importName
= (const char*)p
;
1315 if ( *importName
== '\0' )
1316 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, ordinal
);
1318 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, importName
, ordinal
);
1321 uint64_t address
= read_uleb128(p
, end
);
1322 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1323 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
1324 read_uleb128(p
, end
);
1328 printf("\tnode%03ld;\n", (long)(me
-start
));
1330 const uint8_t childrenCount
= *children
++;
1331 const uint8_t* s
= children
;
1332 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1333 const char* edgeName
= (char*)s
;
1335 while (*s
!= '\0') {
1336 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1339 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1340 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1341 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1342 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1346 template <typename A
>
1347 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1349 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1350 printf("no compressed export info\n");
1353 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1354 const uint8_t* end
= &p
[fInfo
->export_size()];
1355 char cummulativeString
[2000];
1356 printf("digraph {\n");
1357 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1362 template <typename A
>
1363 void DyldInfoPrinter
<A
>::gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
1364 const uint8_t* parent
, const uint8_t* p
,
1365 std::vector
<uint32_t>& nodeStarts
)
1367 nodeStarts
.push_back(p
-start
);
1368 const uint8_t terminalSize
= read_uleb128(p
, end
);
1369 const uint8_t* children
= p
+ terminalSize
;
1371 const uint8_t childrenCount
= *children
++;
1372 const uint8_t* s
= children
;
1373 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1374 // skip over edge string
1378 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1379 gatherNodeStarts(start
, end
, start
, start
+childNodeOffet
, nodeStarts
);
1384 template <typename A
>
1385 void DyldInfoPrinter
<A
>::printExportInfoNodes()
1387 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1388 printf("no compressed export info\n");
1391 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1392 const uint8_t* end
= &start
[fInfo
->export_size()];
1393 std::vector
<uint32_t> nodeStarts
;
1394 gatherNodeStarts(start
, end
, start
, start
, nodeStarts
);
1395 std::sort(nodeStarts
.begin(), nodeStarts
.end());
1396 for (std::vector
<uint32_t>::const_iterator it
=nodeStarts
.begin(); it
!= nodeStarts
.end(); ++it
) {
1397 printf("0x%04X: ", *it
);
1398 const uint8_t* p
= start
+ *it
;
1399 uint64_t exportInfoSize
= read_uleb128(p
, end
);
1400 if ( exportInfoSize
!= 0 ) {
1401 // print terminal info
1402 uint64_t flags
= read_uleb128(p
, end
);
1403 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1404 uint64_t ordinal
= read_uleb128(p
, end
);
1405 const char* importName
= (const char*)p
;
1409 if ( strlen(importName
) == 0 )
1410 printf("[flags=REEXPORT ordinal=%llu] ", ordinal
);
1412 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal
, importName
);
1414 else if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1415 uint64_t stub
= read_uleb128(p
, end
);
1416 uint64_t resolver
= read_uleb128(p
, end
);
1417 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub
, resolver
);
1420 uint64_t address
= read_uleb128(p
, end
);
1421 if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR
)
1422 printf("[addr=0x%06llX] ", address
);
1423 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1424 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address
);
1426 printf("[flags=0x%llX addr=0x%06llX] ", flags
, address
);
1429 // print child edges
1430 const uint8_t childrenCount
= *p
++;
1431 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1432 const char* edgeName
= (const char*)p
;
1436 uint32_t childNodeOffet
= read_uleb128(p
, end
);
1437 printf("%s->0x%04X", edgeName
, childNodeOffet
);
1438 if ( i
< (childrenCount
-1) )
1448 template <typename A
>
1449 const uint8_t* DyldInfoPrinter
<A
>::printSharedRegionInfoForEachULEB128Address(const uint8_t* p
, uint8_t kind
)
1451 const char* kindStr
= "??";
1454 kindStr
= "32-bit pointer";
1457 kindStr
= "64-bit pointer";
1460 kindStr
= "ppc hi16";
1463 kindStr
= "32-bit offset to IMPORT";
1466 kindStr
= "thumb2 movw";
1469 kindStr
= "ARM movw";
1472 kindStr
= "thumb2 movt low high 4 bits=0";
1475 kindStr
= "thumb2 movt low high 4 bits=1";
1478 kindStr
= "thumb2 movt low high 4 bits=2";
1481 kindStr
= "thumb2 movt low high 4 bits=3";
1484 kindStr
= "thumb2 movt low high 4 bits=4";
1487 kindStr
= "thumb2 movt low high 4 bits=5";
1490 kindStr
= "thumb2 movt low high 4 bits=6";
1493 kindStr
= "thumb2 movt low high 4 bits=7";
1496 kindStr
= "thumb2 movt low high 4 bits=8";
1499 kindStr
= "thumb2 movt low high 4 bits=9";
1502 kindStr
= "thumb2 movt low high 4 bits=0xA";
1505 kindStr
= "thumb2 movt low high 4 bits=0xB";
1508 kindStr
= "thumb2 movt low high 4 bits=0xC";
1511 kindStr
= "thumb2 movt low high 4 bits=0xD";
1514 kindStr
= "thumb2 movt low high 4 bits=0xE";
1517 kindStr
= "thumb2 movt low high 4 bits=0xF";
1520 uint64_t address
= 0;
1525 uint8_t byte
= *p
++;
1526 delta
|= ((byte
& 0x7F) << shift
);
1528 if ( byte
< 0x80 ) {
1531 printf("0x%0llX %s\n", address
+fBaseAddress
, kindStr
);
1543 template <typename A
>
1544 void DyldInfoPrinter
<A
>::printSharedRegionInfo()
1546 if ( (fSharedRegionInfo
== NULL
) || (fSharedRegionInfo
->datasize() == 0) ) {
1547 printf("no shared region info\n");
1550 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fSharedRegionInfo
->dataoff();
1551 const uint8_t* infoEnd
= &infoStart
[fSharedRegionInfo
->datasize()];
1552 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
);) {
1553 uint8_t kind
= *p
++;
1554 p
= this->printSharedRegionInfoForEachULEB128Address(p
, kind
);
1560 #if SUPPORT_ARCH_arm_any
1562 void DyldInfoPrinter
<arm
>::printFunctionStartLine(uint64_t addr
)
1565 printf("0x%0llX [thumb] %s\n", (addr
& -2), symbolNameForAddress(addr
& -2));
1567 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1571 template <typename A
>
1572 void DyldInfoPrinter
<A
>::printFunctionStartLine(uint64_t addr
)
1574 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1578 template <typename A
>
1579 void DyldInfoPrinter
<A
>::printFunctionStartsInfo()
1581 if ( (fFunctionStartsInfo
== NULL
) || (fFunctionStartsInfo
->datasize() == 0) ) {
1582 printf("no function starts info\n");
1585 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fFunctionStartsInfo
->dataoff();
1586 const uint8_t* infoEnd
= &infoStart
[fFunctionStartsInfo
->datasize()];
1587 uint64_t address
= fBaseAddress
;
1588 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
); ) {
1593 uint8_t byte
= *p
++;
1594 delta
|= ((byte
& 0x7F) << shift
);
1596 if ( byte
< 0x80 ) {
1598 printFunctionStartLine(address
);
1606 template <typename A
>
1607 void DyldInfoPrinter
<A
>::printDylibsInfo()
1609 printf("attributes dependent dylibs\n");
1610 for(typename
std::vector
<const macho_dylib_command
<P
>*>::iterator it
= fDylibLoadCommands
.begin(); it
!= fDylibLoadCommands
.end(); ++it
) {
1611 const macho_dylib_command
<P
>* dylib
= *it
;
1612 const char* attribute
= "";
1613 switch ( dylib
->cmd() ) {
1614 case LC_LOAD_WEAK_DYLIB
:
1615 attribute
= "weak_import";
1617 case LC_REEXPORT_DYLIB
:
1618 attribute
= "re-export";
1620 case LC_LOAD_UPWARD_DYLIB
:
1621 attribute
= "upward";
1623 case LC_LAZY_LOAD_DYLIB
:
1624 attribute
= "lazy_load";
1630 printf(" %-12s %s\n", attribute
, dylib
->name());
1634 template <typename A
>
1635 void DyldInfoPrinter
<A
>::printDRInfo()
1637 if ( fDRInfo
== NULL
) {
1638 printf("no Designated Requirements info\n");
1641 printf("dylibs DRs\n");
1642 const uint8_t* start
= ((uint8_t*)fHeader
+ fDRInfo
->dataoff());
1643 //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
1644 typedef Security::SuperBlob
<Security::kSecCodeMagicDRList
> DRListSuperBlob
;
1645 typedef Security::SuperBlob
<Security::kSecCodeMagicRequirementSet
> InternalRequirementsSetBlob
;
1646 const DRListSuperBlob
* topBlob
= (DRListSuperBlob
*)start
;
1647 if ( topBlob
->validateBlob(fDRInfo
->datasize()) ) {
1648 if ( topBlob
->count() == fDylibLoadCommands
.size() ) {
1649 for(unsigned i
=0; i
< topBlob
->count(); ++i
) {
1650 printf(" %-20s ", fDylibs
[i
]);
1651 const Security::BlobCore
* item
= topBlob
->find(i
);
1652 if ( item
!= NULL
) {
1653 const uint8_t* itemStart
= (uint8_t*)item
;
1654 const uint8_t* itemEnd
= itemStart
+ item
->length();
1655 for(const uint8_t* p
=itemStart
; p
< itemEnd
; ++p
)
1656 printf("%02X ", *p
);
1659 printf("no DR info");
1665 fprintf(stderr
, "superblob of DRs has a different number of elements than dylib load commands\n");
1669 fprintf(stderr
, "superblob of DRs invalid\n");
1678 template <typename A
>
1679 void DyldInfoPrinter
<A
>::printDataInCode()
1681 if ( fDataInCode
== NULL
) {
1682 printf("no data-in-code info\n");
1685 printf("offset length data-kind\n");
1686 const macho_data_in_code_entry
<P
>* start
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff());
1687 const macho_data_in_code_entry
<P
>* end
= (macho_data_in_code_entry
<P
>*)((uint8_t*)fHeader
+ fDataInCode
->dataoff() + fDataInCode
->datasize());
1688 for (const macho_data_in_code_entry
<P
>* p
=start
; p
< end
; ++p
) {
1689 const char* kindStr
= "???";
1690 switch ( p
->kind() ) {
1695 kindStr
= "jumptable8";
1698 kindStr
= "jumptable16";
1701 kindStr
= "jumptable32";
1704 kindStr
= "jumptable32absolute";
1707 printf("0x%08X 0x%04X %s\n", p
->offset(), p
->length(), kindStr
);
1715 ppc::P::uint_t DyldInfoPrinter
<ppc
>::relocBase()
1717 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1718 return fFirstWritableSegment
->vmaddr();
1720 return fFirstSegment
->vmaddr();
1724 ppc64::P::uint_t DyldInfoPrinter
<ppc64
>::relocBase()
1726 if ( fWriteableSegmentWithAddrOver4G
)
1727 return fFirstWritableSegment
->vmaddr();
1729 return fFirstSegment
->vmaddr();
1733 x86::P::uint_t DyldInfoPrinter
<x86
>::relocBase()
1735 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1736 return fFirstWritableSegment
->vmaddr();
1738 return fFirstSegment
->vmaddr();
1742 x86_64::P::uint_t DyldInfoPrinter
<x86_64
>::relocBase()
1744 // check for split-seg
1745 return fFirstWritableSegment
->vmaddr();
1748 #if SUPPORT_ARCH_arm_any
1750 arm::P::uint_t DyldInfoPrinter
<arm
>::relocBase()
1752 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1753 return fFirstWritableSegment
->vmaddr();
1755 return fFirstSegment
->vmaddr();
1761 const char* DyldInfoPrinter
<ppc
>::relocTypeName(uint8_t r_type
)
1763 if ( r_type
== GENERIC_RELOC_VANILLA
)
1770 const char* DyldInfoPrinter
<ppc64
>::relocTypeName(uint8_t r_type
)
1772 if ( r_type
== GENERIC_RELOC_VANILLA
)
1779 const char* DyldInfoPrinter
<x86
>::relocTypeName(uint8_t r_type
)
1781 if ( r_type
== GENERIC_RELOC_VANILLA
)
1783 else if ( r_type
== GENERIC_RELOC_PB_LA_PTR
)
1784 return "pb pointer";
1790 const char* DyldInfoPrinter
<x86_64
>::relocTypeName(uint8_t r_type
)
1792 if ( r_type
== X86_64_RELOC_UNSIGNED
)
1798 #if SUPPORT_ARCH_arm_any
1800 const char* DyldInfoPrinter
<arm
>::relocTypeName(uint8_t r_type
)
1802 if ( r_type
== ARM_RELOC_VANILLA
)
1804 else if ( r_type
== ARM_RELOC_PB_LA_PTR
)
1805 return "pb pointer";
1811 template <typename A
>
1812 void DyldInfoPrinter
<A
>::printRelocRebaseInfo()
1814 if ( fDynamicSymbolTable
== NULL
) {
1815 printf("no classic dynamic symbol table");
1818 printf("rebase information (from local relocation records and indirect symbol table):\n");
1819 printf("segment section address type\n");
1820 // walk all local relocations
1821 pint_t rbase
= relocBase();
1822 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->locreloff());
1823 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nlocrel()];
1824 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1825 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
1826 pint_t addr
= reloc
->r_address() + rbase
;
1827 uint8_t segIndex
= segmentIndexForAddress(addr
);
1828 const char* typeName
= relocTypeName(reloc
->r_type());
1829 const char* segName
= segmentName(segIndex
);
1830 const char* sectName
= sectionName(segIndex
, addr
);
1831 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1834 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
1835 pint_t addr
= sreloc
->r_address() + rbase
;
1836 uint8_t segIndex
= segmentIndexForAddress(addr
);
1837 const char* typeName
= relocTypeName(sreloc
->r_type());
1838 const char* segName
= segmentName(segIndex
);
1839 const char* sectName
= sectionName(segIndex
, addr
);
1840 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1843 // look for local non-lazy-pointers
1844 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1845 uint8_t segIndex
= 0;
1846 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
, ++segIndex
) {
1847 const macho_segment_command
<P
>* segCmd
= *segit
;
1848 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1849 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1850 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1851 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1852 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
1853 uint32_t indirectOffset
= sect
->reserved1();
1854 uint32_t count
= sect
->size() / sizeof(pint_t
);
1855 for (uint32_t i
=0; i
< count
; ++i
) {
1856 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1857 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
1858 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1859 const char* typeName
= "pointer";
1860 const char* segName
= segmentName(segIndex
);
1861 const char* sectName
= sectionName(segIndex
, addr
);
1862 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1872 template <typename A
>
1873 void DyldInfoPrinter
<A
>::printSymbolTableExportInfo()
1875 if ( fDynamicSymbolTable
== NULL
) {
1876 printf("no classic dynamic symbol table");
1879 printf("export information (from symbol table):\n");
1880 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1881 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1882 const char* flags
= "";
1883 if ( sym
->n_desc() & N_WEAK_DEF
)
1884 flags
= "[weak_def] ";
1886 if ( sym
->n_desc() & N_ARM_THUMB_DEF
)
1888 printf("0x%08llX %s%s\n", sym
->n_value()+thumb
, flags
, &fStrings
[sym
->n_strx()]);
1893 template <typename A
>
1894 const char* DyldInfoPrinter
<A
>::symbolNameForAddress(uint64_t addr
)
1896 if ( fDynamicSymbolTable
!= NULL
) {
1897 // find exact match in globals
1898 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1899 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1900 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1901 return &fStrings
[sym
->n_strx()];
1904 // find exact match in local symbols
1905 const macho_nlist
<P
>* lastLocal
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1906 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()]; sym
< lastLocal
; ++sym
) {
1907 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1908 return &fStrings
[sym
->n_strx()];
1913 // find exact match in all symbols
1914 const macho_nlist
<P
>* lastSym
= &fSymbols
[fSymbolCount
];
1915 for (const macho_nlist
<P
>* sym
= &fSymbols
[0]; sym
< lastSym
; ++sym
) {
1916 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1917 return &fStrings
[sym
->n_strx()];
1925 template <typename A
>
1926 void DyldInfoPrinter
<A
>::printClassicBindingInfo()
1928 if ( fDynamicSymbolTable
== NULL
) {
1929 printf("no classic dynamic symbol table");
1932 printf("binding information (from relocations and indirect symbol table):\n");
1933 printf("segment section address type weak addend dylib symbol\n");
1934 // walk all external relocations
1935 pint_t rbase
= relocBase();
1936 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->extreloff());
1937 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1938 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1939 pint_t addr
= reloc
->r_address() + rbase
;
1940 uint32_t symbolIndex
= reloc
->r_symbolnum();
1941 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1942 const char* symbolName
= &fStrings
[sym
->n_strx()];
1943 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
1944 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1945 uint8_t segIndex
= segmentIndexForAddress(addr
);
1946 const char* typeName
= relocTypeName(reloc
->r_type());
1947 const char* segName
= segmentName(segIndex
);
1948 const char* sectName
= sectionName(segIndex
, addr
);
1949 const pint_t
* addressMapped
= mappedAddressForVMAddress(addr
);
1950 int64_t addend
= P::getP(*addressMapped
);
1951 if ( fHeader
->flags() & MH_PREBOUND
) {
1952 // In prebound binaries the content is already pointing to the target.
1953 // To get the addend requires subtracting out the base address it was prebound to.
1954 addend
-= sym
->n_value();
1956 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1957 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
1959 // look for non-lazy pointers
1960 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1961 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
1962 const macho_segment_command
<P
>* segCmd
= *segit
;
1963 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1964 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1965 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1966 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1967 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
1968 uint32_t indirectOffset
= sect
->reserved1();
1969 uint32_t count
= sect
->size() / sizeof(pint_t
);
1970 for (uint32_t i
=0; i
< count
; ++i
) {
1971 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1972 if ( symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
1973 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1974 const char* symbolName
= &fStrings
[sym
->n_strx()];
1975 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
1976 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1977 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1978 uint8_t segIndex
= segmentIndexForAddress(addr
);
1979 const char* typeName
= "pointer";
1980 const char* segName
= segmentName(segIndex
);
1981 const char* sectName
= sectionName(segIndex
, addr
);
1983 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1984 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
1994 template <typename A
>
1995 void DyldInfoPrinter
<A
>::printClassicLazyBindingInfo()
1997 if ( fDynamicSymbolTable
== NULL
) {
1998 printf("no classic dynamic symbol table");
2001 printf("lazy binding information (from section records and indirect symbol table):\n");
2002 printf("segment section address index dylib symbol\n");
2003 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
2004 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
2005 const macho_segment_command
<P
>* segCmd
= *segit
;
2006 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
2007 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
2008 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2009 uint8_t type
= sect
->flags() & SECTION_TYPE
;
2010 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2011 uint32_t indirectOffset
= sect
->reserved1();
2012 uint32_t count
= sect
->size() / sizeof(pint_t
);
2013 for (uint32_t i
=0; i
< count
; ++i
) {
2014 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2015 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2016 const char* symbolName
= &fStrings
[sym
->n_strx()];
2017 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2018 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
2019 uint8_t segIndex
= segmentIndexForAddress(addr
);
2020 const char* segName
= segmentName(segIndex
);
2021 const char* sectName
= sectionName(segIndex
, addr
);
2022 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2025 else if ( (type
== S_SYMBOL_STUBS
) && (((sect
->flags() & S_ATTR_SELF_MODIFYING_CODE
) != 0)) && (sect
->reserved2() == 5) ) {
2026 // i386 self-modifying stubs
2027 uint32_t indirectOffset
= sect
->reserved1();
2028 uint32_t count
= sect
->size() / 5;
2029 for (uint32_t i
=0; i
< count
; ++i
) {
2030 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
2031 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
2032 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
2033 const char* symbolName
= &fStrings
[sym
->n_strx()];
2034 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
2035 pint_t addr
= sect
->addr() + i
*5;
2036 uint8_t segIndex
= segmentIndexForAddress(addr
);
2037 const char* segName
= segmentName(segIndex
);
2038 const char* sectName
= sectionName(segIndex
, addr
);
2039 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
2048 static void dump(const char* path
)
2050 struct stat stat_buf
;
2053 int fd
= ::open(path
, O_RDONLY
, 0);
2055 throw "cannot open file";
2056 if ( ::fstat(fd
, &stat_buf
) != 0 )
2057 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
2058 uint32_t length
= stat_buf
.st_size
;
2059 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
2060 if ( p
== ((uint8_t*)(-1)) )
2061 throw "cannot map file";
2063 const mach_header
* mh
= (mach_header
*)p
;
2064 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2065 const struct fat_header
* fh
= (struct fat_header
*)p
;
2066 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
2067 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2068 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2069 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
2070 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
2071 cpu_type_t cpusubtype
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
);
2072 if ( ((cputype
== sPreferredArch
)
2073 && ((sPreferredSubArch
==0) || (sPreferredSubArch
==cpusubtype
)))
2074 || (sPreferredArch
== 0) ) {
2076 case CPU_TYPE_POWERPC
:
2077 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
2078 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2080 throw "in universal file, ppc slice does not contain ppc mach-o";
2083 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
2084 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2086 throw "in universal file, i386 slice does not contain i386 mach-o";
2088 case CPU_TYPE_POWERPC64
:
2089 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
2090 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2092 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
2094 case CPU_TYPE_X86_64
:
2095 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
2096 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2098 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
2100 #if SUPPORT_ARCH_arm_any
2102 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
2103 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
, (sPreferredArch
== 0));
2105 throw "in universal file, arm slice does not contain arm mach-o";
2109 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
2114 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
2115 DyldInfoPrinter
<x86
>::make(p
, length
, path
, false);
2117 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
2118 DyldInfoPrinter
<ppc
>::make(p
, length
, path
, false);
2120 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
2121 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
, false);
2123 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
2124 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
, false);
2126 #if SUPPORT_ARCH_arm_any
2127 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
2128 DyldInfoPrinter
<arm
>::make(p
, length
, path
, false);
2132 throw "not a known file type";
2135 catch (const char* msg
) {
2136 throwf("%s in %s", msg
, path
);
2142 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
2143 "\t-dylibs print dependent dylibs\n"
2144 "\t-dr print dependent dylibs and show any recorded DR info\n"
2145 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
2146 "\t-bind print addresses dyld will set based on symbolic lookups\n"
2147 "\t-weak_bind print symbols which dyld must coalesce\n"
2148 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
2149 "\t-export print addresses of all symbols this file exports\n"
2150 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
2151 "\t-function_starts print table of function start addresses\n"
2152 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
2153 "\t-data_in_code print any data-in-code inforamtion\n"
2158 int main(int argc
, const char* argv
[])
2166 std::vector
<const char*> files
;
2167 for(int i
=1; i
< argc
; ++i
) {
2168 const char* arg
= argv
[i
];
2169 if ( arg
[0] == '-' ) {
2170 if ( strcmp(arg
, "-arch") == 0 ) {
2171 const char* arch
= ++i
<argc
? argv
[i
]: "";
2172 if ( strcmp(arch
, "ppc64") == 0 )
2173 sPreferredArch
= CPU_TYPE_POWERPC64
;
2174 else if ( strcmp(arch
, "ppc") == 0 )
2175 sPreferredArch
= CPU_TYPE_POWERPC
;
2176 else if ( strcmp(arch
, "i386") == 0 )
2177 sPreferredArch
= CPU_TYPE_I386
;
2178 else if ( strcmp(arch
, "x86_64") == 0 )
2179 sPreferredArch
= CPU_TYPE_X86_64
;
2181 const char* archName
= argv
[++i
];
2182 if ( archName
== NULL
)
2183 throw "-arch missing architecture name";
2185 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
2186 if ( strcmp(t
->archName
,archName
) == 0 ) {
2187 sPreferredArch
= t
->cpuType
;
2189 sPreferredSubArch
= t
->cpuSubType
;
2193 throwf("unknown architecture %s", archName
);
2196 else if ( strcmp(arg
, "-rebase") == 0 ) {
2199 else if ( strcmp(arg
, "-bind") == 0 ) {
2202 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
2203 printWeakBind
= true;
2205 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
2206 printLazyBind
= true;
2208 else if ( strcmp(arg
, "-export") == 0 ) {
2211 else if ( strcmp(arg
, "-opcodes") == 0 ) {
2212 printOpcodes
= true;
2214 else if ( strcmp(arg
, "-export_dot") == 0 ) {
2215 printExportGraph
= true;
2217 else if ( strcmp(arg
, "-export_trie_nodes") == 0 ) {
2218 printExportNodes
= true;
2220 else if ( strcmp(arg
, "-shared_region") == 0 ) {
2221 printSharedRegion
= true;
2223 else if ( strcmp(arg
, "-function_starts") == 0 ) {
2224 printFunctionStarts
= true;
2226 else if ( strcmp(arg
, "-dylibs") == 0 ) {
2229 else if ( strcmp(arg
, "-dr") == 0 ) {
2232 else if ( strcmp(arg
, "-data_in_code") == 0 ) {
2233 printDataCode
= true;
2236 throwf("unknown option: %s\n", arg
);
2240 files
.push_back(arg
);
2243 if ( files
.size() == 0 )
2245 if ( files
.size() == 1 ) {
2249 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
2250 printf("\n%s:\n", *it
);
2255 catch (const char* msg
) {
2256 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);