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"
42 static bool printRebase
= false;
43 static bool printBind
= false;
44 static bool printWeakBind
= false;
45 static bool printLazyBind
= false;
46 static bool printOpcodes
= false;
47 static bool printExport
= false;
48 static bool printExportGraph
= false;
49 static bool printExportNodes
= false;
50 static bool printSharedRegion
= false;
51 static bool printFunctionStarts
= false;
52 static bool printDylibs
= false;
53 static cpu_type_t sPreferredArch
= CPU_TYPE_I386
;
54 static cpu_type_t sPreferredSubArch
= 0;
57 __attribute__((noreturn
))
58 static void throwf(const char* format
, ...)
62 va_start(list
, format
);
63 vasprintf(&p
, format
, list
);
75 static bool validFile(const uint8_t* fileContent
);
76 static DyldInfoPrinter
<A
>* make(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
)
77 { return new DyldInfoPrinter
<A
>(fileContent
, fileLength
, path
); }
78 virtual ~DyldInfoPrinter() {}
82 typedef typename
A::P P
;
83 typedef typename
A::P::E E
;
84 typedef typename
A::P::uint_t pint_t
;
89 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
92 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> StringSet
;
94 DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
);
95 void printRebaseInfo();
96 void printRebaseInfoOpcodes();
97 void printBindingInfo();
98 void printWeakBindingInfo();
99 void printLazyBindingInfo();
100 void printBindingInfoOpcodes(bool weakBinding
);
101 void printWeakBindingInfoOpcodes();
102 void printLazyBindingOpcodes();
103 void printExportInfo();
104 void printExportInfoGraph();
105 void printExportInfoNodes();
106 void printRelocRebaseInfo();
107 void printSymbolTableExportInfo();
108 void printClassicLazyBindingInfo();
109 void printClassicBindingInfo();
110 void printSharedRegionInfo();
111 void printFunctionStartsInfo();
112 void printDylibsInfo();
113 void printFunctionStartLine(uint64_t addr
);
114 const uint8_t* printSharedRegionInfoForEachULEB128Address(const uint8_t* p
, uint8_t kind
);
116 const char* relocTypeName(uint8_t r_type
);
117 uint8_t segmentIndexForAddress(pint_t addr
);
118 void processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
119 const uint8_t* parent
, const uint8_t* p
,
120 char* cummulativeString
, int curStrOffset
);
121 void gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
122 const uint8_t* parent
, const uint8_t* p
,
123 std::vector
<uint32_t>& nodeStarts
);
124 const char* rebaseTypeName(uint8_t type
);
125 const char* bindTypeName(uint8_t type
);
126 pint_t
segStartAddress(uint8_t segIndex
);
127 const char* segmentName(uint8_t segIndex
);
128 const char* sectionName(uint8_t segIndex
, pint_t address
);
129 const char* getSegAndSectName(uint8_t segIndex
, pint_t address
);
130 const char* ordinalName(int libraryOrdinal
);
131 const char* classicOrdinalName(int libraryOrdinal
);
132 pint_t
* mappedAddressForVMAddress(pint_t vmaddress
);
133 const char* symbolNameForAddress(uint64_t);
137 const macho_header
<P
>* fHeader
;
139 const char* fStrings
;
140 const char* fStringsEnd
;
141 const macho_nlist
<P
>* fSymbols
;
142 uint32_t fSymbolCount
;
143 const macho_dyld_info_command
<P
>* fInfo
;
144 const macho_linkedit_data_command
<P
>* fSharedRegionInfo
;
145 const macho_linkedit_data_command
<P
>* fFunctionStartsInfo
;
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()) {
177 bool DyldInfoPrinter
<ppc64
>::validFile(const uint8_t* fileContent
)
179 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
180 if ( header
->magic() != MH_MAGIC_64
)
182 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
184 switch (header
->filetype()) {
195 bool DyldInfoPrinter
<x86
>::validFile(const uint8_t* fileContent
)
197 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
198 if ( header
->magic() != MH_MAGIC
)
200 if ( header
->cputype() != CPU_TYPE_I386
)
202 switch (header
->filetype()) {
213 bool DyldInfoPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
215 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
216 if ( header
->magic() != MH_MAGIC_64
)
218 if ( header
->cputype() != CPU_TYPE_X86_64
)
220 switch (header
->filetype()) {
231 bool DyldInfoPrinter
<arm
>::validFile(const uint8_t* fileContent
)
233 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
234 if ( header
->magic() != MH_MAGIC
)
236 if ( header
->cputype() != CPU_TYPE_ARM
)
238 switch (header
->filetype()) {
248 template <typename A
>
249 DyldInfoPrinter
<A
>::DyldInfoPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
)
250 : fHeader(NULL
), fLength(fileLength
),
251 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fInfo(NULL
),
252 fSharedRegionInfo(NULL
), fFunctionStartsInfo(NULL
),
253 fBaseAddress(0), fDynamicSymbolTable(NULL
), fFirstSegment(NULL
), fFirstWritableSegment(NULL
),
254 fWriteableSegmentWithAddrOver4G(false)
257 if ( ! validFile(fileContent
) )
258 throw "not a mach-o file that can be checked";
260 fPath
= strdup(path
);
261 fHeader
= (const macho_header
<P
>*)fileContent
;
264 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
265 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
266 const uint32_t cmd_count
= fHeader
->ncmds();
267 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
268 const macho_load_command
<P
>* cmd
= cmds
;
269 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
270 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
271 if ( endOfCmd
> endOfLoadCommands
)
272 throwf("load command #%d extends beyond the end of the load commands", i
);
273 if ( endOfCmd
> endOfFile
)
274 throwf("load command #%d extends beyond the end of the file", i
);
275 switch ( cmd
->cmd() ) {
277 case LC_DYLD_INFO_ONLY
:
278 fInfo
= (macho_dyld_info_command
<P
>*)cmd
;
280 case macho_segment_command
<P
>::CMD
:
282 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
283 fSegments
.push_back(segCmd
);
284 if ( (segCmd
->fileoff() == 0) && (segCmd
->filesize() != 0) )
285 fBaseAddress
= segCmd
->vmaddr();
286 if ( fFirstSegment
== NULL
)
287 fFirstSegment
= segCmd
;
288 if ( (segCmd
->initprot() & VM_PROT_WRITE
) != 0 ) {
289 if ( fFirstWritableSegment
== NULL
)
290 fFirstWritableSegment
= segCmd
;
291 if ( segCmd
->vmaddr() > 0x100000000ULL
)
292 fWriteableSegmentWithAddrOver4G
= true;
297 case LC_LOAD_WEAK_DYLIB
:
298 case LC_REEXPORT_DYLIB
:
299 case LC_LOAD_UPWARD_DYLIB
:
300 case LC_LAZY_LOAD_DYLIB
:
302 const macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
303 fDylibLoadCommands
.push_back(dylib
);
304 const char* lastSlash
= strrchr(dylib
->name(), '/');
305 const char* leafName
= (lastSlash
!= NULL
) ? lastSlash
+1 : dylib
->name();
306 const char* firstDot
= strchr(leafName
, '.');
307 if ( firstDot
!= NULL
) {
308 char* t
= strdup(leafName
);
309 t
[firstDot
-leafName
] = '\0';
310 fDylibs
.push_back(t
);
313 fDylibs
.push_back(leafName
);
318 fDynamicSymbolTable
= (macho_dysymtab_command
<P
>*)cmd
;
322 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
323 fSymbolCount
= symtab
->nsyms();
324 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
325 fStrings
= (char*)fHeader
+ symtab
->stroff();
326 fStringsEnd
= fStrings
+ symtab
->strsize();
329 case LC_SEGMENT_SPLIT_INFO
:
330 fSharedRegionInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
332 case LC_FUNCTION_STARTS
:
333 fFunctionStartsInfo
= (macho_linkedit_data_command
<P
>*)cmd
;
336 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
343 printRelocRebaseInfo();
349 printClassicBindingInfo();
352 printWeakBindingInfo();
353 if ( printLazyBind
) {
355 printLazyBindingInfo();
357 printClassicLazyBindingInfo();
363 printSymbolTableExportInfo();
365 if ( printOpcodes
) {
366 printRebaseInfoOpcodes();
367 printBindingInfoOpcodes(false);
368 printBindingInfoOpcodes(true);
369 printLazyBindingOpcodes();
371 if ( printExportGraph
)
372 printExportInfoGraph();
373 if ( printExportNodes
)
374 printExportInfoNodes();
375 if ( printSharedRegion
)
376 printSharedRegionInfo();
377 if ( printFunctionStarts
)
378 printFunctionStartsInfo();
383 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
389 throwf("malformed uleb128");
391 uint64_t slice
= *p
& 0x7f;
393 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
394 throwf("uleb128 too big");
396 result
|= (slice
<< bit
);
404 static int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
411 throwf("malformed sleb128");
413 result
|= ((byte
& 0x7f) << bit
);
415 } while (byte
& 0x80);
416 // sign extend negative numbers
417 if ( (byte
& 0x40) != 0 )
418 result
|= (-1LL) << bit
;
423 template <typename A
>
424 const char* DyldInfoPrinter
<A
>::rebaseTypeName(uint8_t type
)
427 case REBASE_TYPE_POINTER
:
429 case REBASE_TYPE_TEXT_ABSOLUTE32
:
431 case REBASE_TYPE_TEXT_PCREL32
:
434 return "!!unknown!!";
438 template <typename A
>
439 const char* DyldInfoPrinter
<A
>::bindTypeName(uint8_t type
)
442 case BIND_TYPE_POINTER
:
444 case BIND_TYPE_TEXT_ABSOLUTE32
:
446 case BIND_TYPE_TEXT_PCREL32
:
449 return "!!unknown!!";
453 template <typename A
>
454 typename
A::P::uint_t DyldInfoPrinter
<A
>::segStartAddress(uint8_t segIndex
)
456 if ( segIndex
> fSegments
.size() )
457 throw "segment index out of range";
458 return fSegments
[segIndex
]->vmaddr();
461 template <typename A
>
462 const char* DyldInfoPrinter
<A
>::segmentName(uint8_t segIndex
)
464 if ( segIndex
> fSegments
.size() )
465 throw "segment index out of range";
466 return fSegments
[segIndex
]->segname();
469 template <typename A
>
470 const char* DyldInfoPrinter
<A
>::sectionName(uint8_t segIndex
, pint_t address
)
472 if ( segIndex
> fSegments
.size() )
473 throw "segment index out of range";
474 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
475 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
476 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
477 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
478 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
479 if ( strlen(sect
->sectname()) > 15 ) {
480 static char temp
[18];
481 strlcpy(temp
, sect
->sectname(), 17);
485 return sect
->sectname();
492 template <typename A
>
493 const char* DyldInfoPrinter
<A
>::getSegAndSectName(uint8_t segIndex
, pint_t address
)
495 static char buffer
[64];
496 strcpy(buffer
, segmentName(segIndex
));
498 const macho_segment_command
<P
>* segCmd
= fSegments
[segIndex
];
499 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
500 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
501 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
502 if ( (sect
->addr() <= address
) && (address
< (sect
->addr()+sect
->size())) ) {
503 // section name may not be zero terminated
504 char* end
= &buffer
[strlen(buffer
)];
505 strlcpy(end
, sect
->sectname(), 16);
512 template <typename A
>
513 uint8_t DyldInfoPrinter
<A
>::segmentIndexForAddress(pint_t address
)
515 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
516 if ( (fSegments
[i
]->vmaddr() <= address
) && (address
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
520 throwf("address 0x%llX is not in any segment", (uint64_t)address
);
523 template <typename A
>
524 typename
A::P::uint_t
* DyldInfoPrinter
<A
>::mappedAddressForVMAddress(pint_t vmaddress
)
526 for(unsigned int i
=0; i
< fSegments
.size(); ++i
) {
527 if ( (fSegments
[i
]->vmaddr() <= vmaddress
) && (vmaddress
< (fSegments
[i
]->vmaddr()+fSegments
[i
]->vmsize())) ) {
528 unsigned long offsetInMappedFile
= fSegments
[i
]->fileoff()+vmaddress
-fSegments
[i
]->vmaddr();
529 return (pint_t
*)((uint8_t*)fHeader
+ offsetInMappedFile
);
532 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress
);
535 template <typename A
>
536 const char* DyldInfoPrinter
<A
>::ordinalName(int libraryOrdinal
)
538 switch ( libraryOrdinal
) {
539 case BIND_SPECIAL_DYLIB_SELF
:
541 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
542 return "main-executable";
543 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
544 return "flat-namespace";
546 if ( libraryOrdinal
< BIND_SPECIAL_DYLIB_FLAT_LOOKUP
)
547 throw "unknown special ordinal";
548 if ( libraryOrdinal
> (int)fDylibs
.size() )
549 throw "libraryOrdinal out of range";
550 return fDylibs
[libraryOrdinal
-1];
553 template <typename A
>
554 const char* DyldInfoPrinter
<A
>::classicOrdinalName(int libraryOrdinal
)
556 if ( (fHeader
->flags() & MH_TWOLEVEL
) == 0 )
557 return "flat-namespace";
558 switch ( libraryOrdinal
) {
559 case SELF_LIBRARY_ORDINAL
:
561 case EXECUTABLE_ORDINAL
:
562 return "main-executable";
563 case DYNAMIC_LOOKUP_ORDINAL
:
564 return "flat-namespace";
566 if ( libraryOrdinal
> (int)fDylibs
.size() )
567 throw "libraryOrdinal out of range";
568 return fDylibs
[libraryOrdinal
-1];
571 template <typename A
>
572 void DyldInfoPrinter
<A
>::printRebaseInfo()
574 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
575 printf("no compressed rebase info\n");
578 printf("rebase information (from compressed dyld info):\n");
579 printf("segment section address type\n");
581 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
582 const uint8_t* end
= &p
[fInfo
->rebase_size()];
585 uint64_t segOffset
= 0;
589 pint_t segStartAddr
= 0;
590 const char* segName
= "??";
591 const char* typeName
= "??";
593 while ( !done
&& (p
< end
) ) {
594 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
595 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
598 case REBASE_OPCODE_DONE
:
601 case REBASE_OPCODE_SET_TYPE_IMM
:
603 typeName
= rebaseTypeName(type
);
605 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
606 segIndex
= immediate
;
607 segStartAddr
= segStartAddress(segIndex
);
608 segName
= segmentName(segIndex
);
609 segOffset
= read_uleb128(p
, end
);
611 case REBASE_OPCODE_ADD_ADDR_ULEB
:
612 segOffset
+= read_uleb128(p
, end
);
614 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
615 segOffset
+= immediate
*sizeof(pint_t
);
617 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
618 for (int i
=0; i
< immediate
; ++i
) {
619 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
620 segOffset
+= sizeof(pint_t
);
623 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
624 count
= read_uleb128(p
, end
);
625 for (uint32_t i
=0; i
< count
; ++i
) {
626 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
627 segOffset
+= sizeof(pint_t
);
630 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
631 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
632 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
634 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
635 count
= read_uleb128(p
, end
);
636 skip
= read_uleb128(p
, end
);
637 for (uint32_t i
=0; i
< count
; ++i
) {
638 printf("%-7s %-16s 0x%08llX %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
);
639 segOffset
+= skip
+ sizeof(pint_t
);
643 throwf("bad rebase opcode %d", *p
);
652 template <typename A
>
653 void DyldInfoPrinter
<A
>::printRebaseInfoOpcodes()
655 if ( (fInfo
== NULL
) || (fInfo
->rebase_off() == 0) ) {
656 printf("no compressed rebase info\n");
659 printf("rebase opcodes:\n");
660 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->rebase_off();
661 const uint8_t* end
= &p
[fInfo
->rebase_size()];
664 uint64_t address
= fBaseAddress
;
667 unsigned int segmentIndex
;
669 while ( !done
&& (p
< end
) ) {
670 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
671 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
674 case REBASE_OPCODE_DONE
:
676 printf("REBASE_OPCODE_DONE()\n");
678 case REBASE_OPCODE_SET_TYPE_IMM
:
680 printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type
);
682 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
683 segmentIndex
= immediate
;
684 address
= read_uleb128(p
, end
);
685 printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex
, address
);
687 case REBASE_OPCODE_ADD_ADDR_ULEB
:
688 address
= read_uleb128(p
, end
);
689 printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address
);
691 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
692 address
= immediate
*sizeof(pint_t
);
693 printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address
);
695 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
696 printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate
);
698 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
699 count
= read_uleb128(p
, end
);
700 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count
);
702 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
703 skip
= read_uleb128(p
, end
) + sizeof(pint_t
);
704 printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip
);
706 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
707 count
= read_uleb128(p
, end
);
708 skip
= read_uleb128(p
, end
);
709 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count
, skip
);
712 throwf("bad rebase opcode %d", *p
);
724 template <typename A
>
725 void DyldInfoPrinter
<A
>::printBindingInfoOpcodes(bool weakbinding
)
727 if ( fInfo
== NULL
) {
728 printf("no compressed binding info\n");
730 else if ( !weakbinding
&& (fInfo
->bind_off() == 0) ) {
731 printf("no compressed binding info\n");
733 else if ( weakbinding
&& (fInfo
->weak_bind_off() == 0) ) {
734 printf("no compressed weak binding info\n");
737 const uint8_t* start
;
740 printf("weak binding opcodes:\n");
741 start
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
742 end
= &start
[fInfo
->weak_bind_size()];
745 printf("binding opcodes:\n");
746 start
= (uint8_t*)fHeader
+ fInfo
->bind_off();
747 end
= &start
[fInfo
->bind_size()];
749 const uint8_t* p
= start
;
752 uint64_t address
= fBaseAddress
;
753 const char* symbolName
= NULL
;
754 int libraryOrdinal
= 0;
756 uint32_t segmentIndex
= 0;
760 while ( !done
&& (p
< end
) ) {
761 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
762 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
763 uint32_t opcodeOffset
= p
-start
;
766 case BIND_OPCODE_DONE
:
768 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
770 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
771 libraryOrdinal
= immediate
;
772 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
774 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
775 libraryOrdinal
= read_uleb128(p
, end
);
776 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
778 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
779 // the special ordinals are negative numbers
780 if ( immediate
== 0 )
783 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
784 libraryOrdinal
= signExtended
;
786 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
788 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
790 symbolName
= (char*)p
;
794 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
796 case BIND_OPCODE_SET_TYPE_IMM
:
798 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
800 case BIND_OPCODE_SET_ADDEND_SLEB
:
801 addend
= read_sleb128(p
, end
);
802 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
804 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
805 segmentIndex
= immediate
;
806 address
= read_uleb128(p
, end
);
807 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
809 case BIND_OPCODE_ADD_ADDR_ULEB
:
810 skip
= read_uleb128(p
, end
);
811 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
813 case BIND_OPCODE_DO_BIND
:
814 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
816 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
817 skip
= read_uleb128(p
, end
);
818 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
820 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
821 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
822 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
824 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
825 count
= read_uleb128(p
, end
);
826 skip
= read_uleb128(p
, end
);
827 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
830 throwf("unknown bind opcode %d", *p
);
839 template <typename A
>
840 void DyldInfoPrinter
<A
>::printBindingInfo()
842 if ( (fInfo
== NULL
) || (fInfo
->bind_off() == 0) ) {
843 printf("no compressed binding info\n");
846 printf("bind information:\n");
847 printf("segment section address type addend dylib symbol\n");
848 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->bind_off();
849 const uint8_t* end
= &p
[fInfo
->bind_size()];
852 uint8_t segIndex
= 0;
853 uint64_t segOffset
= 0;
854 const char* symbolName
= NULL
;
855 const char* fromDylib
= "??";
856 int libraryOrdinal
= 0;
860 pint_t segStartAddr
= 0;
861 const char* segName
= "??";
862 const char* typeName
= "??";
863 const char* weak_import
= "";
865 while ( !done
&& (p
< end
) ) {
866 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
867 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
870 case BIND_OPCODE_DONE
:
873 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
874 libraryOrdinal
= immediate
;
875 fromDylib
= ordinalName(libraryOrdinal
);
877 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
878 libraryOrdinal
= read_uleb128(p
, end
);
879 fromDylib
= ordinalName(libraryOrdinal
);
881 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
882 // the special ordinals are negative numbers
883 if ( immediate
== 0 )
886 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
887 libraryOrdinal
= signExtended
;
889 fromDylib
= ordinalName(libraryOrdinal
);
891 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
892 symbolName
= (char*)p
;
896 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
897 weak_import
= " (weak import)";
901 case BIND_OPCODE_SET_TYPE_IMM
:
903 typeName
= bindTypeName(type
);
905 case BIND_OPCODE_SET_ADDEND_SLEB
:
906 addend
= read_sleb128(p
, end
);
908 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
909 segIndex
= immediate
;
910 segStartAddr
= segStartAddress(segIndex
);
911 segName
= segmentName(segIndex
);
912 segOffset
= read_uleb128(p
, end
);
914 case BIND_OPCODE_ADD_ADDR_ULEB
:
915 segOffset
+= read_uleb128(p
, end
);
917 case BIND_OPCODE_DO_BIND
:
918 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
919 segOffset
+= sizeof(pint_t
);
921 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
922 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
923 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
925 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
926 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
927 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
929 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
930 count
= read_uleb128(p
, end
);
931 skip
= read_uleb128(p
, end
);
932 for (uint32_t i
=0; i
< count
; ++i
) {
933 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, fromDylib
, symbolName
, weak_import
);
934 segOffset
+= skip
+ sizeof(pint_t
);
938 throwf("bad bind opcode %d", *p
);
945 template <typename A
>
946 void DyldInfoPrinter
<A
>::printWeakBindingInfo()
948 if ( (fInfo
== NULL
) || (fInfo
->weak_bind_off() == 0) ) {
949 printf("no weak binding\n");
952 printf("weak binding information:\n");
953 printf("segment section address type addend symbol\n");
954 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->weak_bind_off();
955 const uint8_t* end
= &p
[fInfo
->weak_bind_size()];
958 uint8_t segIndex
= 0;
959 uint64_t segOffset
= 0;
960 const char* symbolName
= NULL
;
964 pint_t segStartAddr
= 0;
965 const char* segName
= "??";
966 const char* typeName
= "??";
968 while ( !done
&& (p
< end
) ) {
969 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
970 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
973 case BIND_OPCODE_DONE
:
976 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
977 symbolName
= (char*)p
;
981 if ( (immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) != 0 )
982 printf(" strong %s\n", symbolName
);
984 case BIND_OPCODE_SET_TYPE_IMM
:
986 typeName
= bindTypeName(type
);
988 case BIND_OPCODE_SET_ADDEND_SLEB
:
989 addend
= read_sleb128(p
, end
);
991 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
992 segIndex
= immediate
;
993 segStartAddr
= segStartAddress(segIndex
);
994 segName
= segmentName(segIndex
);
995 segOffset
= read_uleb128(p
, end
);
997 case BIND_OPCODE_ADD_ADDR_ULEB
:
998 segOffset
+= read_uleb128(p
, end
);
1000 case BIND_OPCODE_DO_BIND
:
1001 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1002 segOffset
+= sizeof(pint_t
);
1004 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1005 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1006 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1008 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1009 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1010 segOffset
+= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1012 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1013 count
= read_uleb128(p
, end
);
1014 skip
= read_uleb128(p
, end
);
1015 for (uint32_t i
=0; i
< count
; ++i
) {
1016 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, typeName
, addend
, symbolName
);
1017 segOffset
+= skip
+ sizeof(pint_t
);
1021 throwf("unknown weak bind opcode %d", *p
);
1029 template <typename A
>
1030 void DyldInfoPrinter
<A
>::printLazyBindingInfo()
1032 if ( fInfo
== NULL
) {
1033 printf("no compressed dyld info\n");
1035 else if ( fInfo
->lazy_bind_off() == 0 ) {
1036 printf("no compressed lazy binding info\n");
1039 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1040 printf("segment section address index dylib symbol\n");
1041 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1042 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1044 uint8_t type
= BIND_TYPE_POINTER
;
1045 uint8_t segIndex
= 0;
1046 uint64_t segOffset
= 0;
1047 const char* symbolName
= NULL
;
1048 const char* fromDylib
= "??";
1049 int libraryOrdinal
= 0;
1051 uint32_t lazy_offset
= 0;
1052 pint_t segStartAddr
= 0;
1053 const char* segName
= "??";
1054 const char* typeName
= "??";
1055 const char* weak_import
= "";
1056 for (const uint8_t* p
=start
; p
< end
; ) {
1057 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1058 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1061 case BIND_OPCODE_DONE
:
1062 lazy_offset
= p
-start
;
1064 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1065 libraryOrdinal
= immediate
;
1066 fromDylib
= ordinalName(libraryOrdinal
);
1068 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1069 libraryOrdinal
= read_uleb128(p
, end
);
1070 fromDylib
= ordinalName(libraryOrdinal
);
1072 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1073 // the special ordinals are negative numbers
1074 if ( immediate
== 0 )
1077 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1078 libraryOrdinal
= signExtended
;
1080 fromDylib
= ordinalName(libraryOrdinal
);
1082 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1083 symbolName
= (char*)p
;
1087 if ( (immediate
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
) != 0 )
1088 weak_import
= " (weak import)";
1092 case BIND_OPCODE_SET_TYPE_IMM
:
1094 typeName
= bindTypeName(type
);
1096 case BIND_OPCODE_SET_ADDEND_SLEB
:
1097 addend
= read_sleb128(p
, end
);
1099 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1100 segIndex
= immediate
;
1101 segStartAddr
= segStartAddress(segIndex
);
1102 segName
= segmentName(segIndex
);
1103 segOffset
= read_uleb128(p
, end
);
1105 case BIND_OPCODE_ADD_ADDR_ULEB
:
1106 segOffset
+= read_uleb128(p
, end
);
1108 case BIND_OPCODE_DO_BIND
:
1109 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName
, sectionName(segIndex
, segStartAddr
+segOffset
), segStartAddr
+segOffset
, lazy_offset
, fromDylib
, symbolName
, weak_import
);
1110 segOffset
+= sizeof(pint_t
);
1113 throwf("bad lazy bind opcode %d", *p
);
1120 template <typename A
>
1121 void DyldInfoPrinter
<A
>::printLazyBindingOpcodes()
1123 if ( fInfo
== NULL
) {
1124 printf("no compressed dyld info\n");
1126 else if ( fInfo
->lazy_bind_off() == 0 ) {
1127 printf("no compressed lazy binding info\n");
1130 printf("lazy binding opcodes:\n");
1131 const uint8_t* const start
= (uint8_t*)fHeader
+ fInfo
->lazy_bind_off();
1132 const uint8_t* const end
= &start
[fInfo
->lazy_bind_size()];
1133 uint8_t type
= BIND_TYPE_POINTER
;
1135 uint64_t address
= fBaseAddress
;
1136 const char* symbolName
= NULL
;
1137 int libraryOrdinal
= 0;
1139 uint32_t segmentIndex
= 0;
1142 for (const uint8_t* p
= start
; p
< end
; ) {
1143 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1144 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1145 uint32_t opcodeOffset
= p
-start
;
1148 case BIND_OPCODE_DONE
:
1149 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset
);
1151 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1152 libraryOrdinal
= immediate
;
1153 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1155 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1156 libraryOrdinal
= read_uleb128(p
, end
);
1157 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset
, libraryOrdinal
);
1159 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1160 // the special ordinals are negative numbers
1161 if ( immediate
== 0 )
1164 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1165 libraryOrdinal
= signExtended
;
1167 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset
, libraryOrdinal
);
1169 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1171 symbolName
= (char*)p
;
1175 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset
, flags
, symbolName
);
1177 case BIND_OPCODE_SET_TYPE_IMM
:
1179 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset
, type
);
1181 case BIND_OPCODE_SET_ADDEND_SLEB
:
1182 addend
= read_sleb128(p
, end
);
1183 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset
, addend
);
1185 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1186 segmentIndex
= immediate
;
1187 address
= read_uleb128(p
, end
);
1188 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset
, segmentIndex
, address
);
1190 case BIND_OPCODE_ADD_ADDR_ULEB
:
1191 skip
= read_uleb128(p
, end
);
1192 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1194 case BIND_OPCODE_DO_BIND
:
1195 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset
);
1197 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1198 skip
= read_uleb128(p
, end
);
1199 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset
, skip
);
1201 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1202 skip
= immediate
*sizeof(pint_t
) + sizeof(pint_t
);
1203 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset
, skip
);
1205 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
1206 count
= read_uleb128(p
, end
);
1207 skip
= read_uleb128(p
, end
);
1208 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset
, count
, skip
);
1211 throwf("unknown bind opcode %d", *p
);
1218 struct SortExportsByAddress
1220 bool operator()(const mach_o::trie::Entry
& left
, const mach_o::trie::Entry
& right
)
1222 return ( left
.address
< right
.address
);
1226 template <typename A
>
1227 void DyldInfoPrinter
<A
>::printExportInfo()
1229 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1230 printf("no compressed export info\n");
1233 printf("export information (from trie):\n");
1234 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1235 const uint8_t* end
= &start
[fInfo
->export_size()];
1236 std::vector
<mach_o::trie::Entry
> list
;
1237 parseTrie(start
, end
, list
);
1238 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1239 for (std::vector
<mach_o::trie::Entry
>::iterator it
=list
.begin(); it
!= list
.end(); ++it
) {
1240 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1241 if ( it
->importName
[0] == '\0' )
1242 fprintf(stdout
, "[re-export] %s from dylib=%llu\n", it
->name
, it
->other
);
1244 fprintf(stdout
, "[re-export] %s from dylib=%llu named=%s\n", it
->name
, it
->other
, it
->importName
);
1247 const char* flags
= "";
1248 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
)
1249 flags
= "[weak_def] ";
1250 else if ( (it
->flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1251 flags
= "[per-thread] ";
1252 if ( it
->flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1253 flags
= "[resolver] ";
1254 fprintf(stdout
, "0x%08llX %s%s (resolver=0x%08llX)\n", fBaseAddress
+it
->address
, flags
, it
->name
, it
->other
);
1257 fprintf(stdout
, "0x%08llX %s%s\n", fBaseAddress
+it
->address
, flags
, it
->name
);
1265 template <typename A
>
1266 void DyldInfoPrinter
<A
>::processExportGraphNode(const uint8_t* const start
, const uint8_t* const end
,
1267 const uint8_t* parent
, const uint8_t* p
,
1268 char* cummulativeString
, int curStrOffset
)
1270 const uint8_t* const me
= p
;
1271 const uint8_t terminalSize
= read_uleb128(p
, end
);
1272 const uint8_t* children
= p
+ terminalSize
;
1273 if ( terminalSize
!= 0 ) {
1274 uint32_t flags
= read_uleb128(p
, end
);
1275 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1276 uint64_t ordinal
= read_uleb128(p
, end
);
1277 const char* importName
= (const char*)p
;
1281 if ( *importName
== '\0' )
1282 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, ordinal
);
1284 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me
-start
), cummulativeString
, importName
, ordinal
);
1287 uint64_t address
= read_uleb128(p
, end
);
1288 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me
-start
), cummulativeString
, address
);
1289 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
1290 read_uleb128(p
, end
);
1294 printf("\tnode%03ld;\n", (long)(me
-start
));
1296 const uint8_t childrenCount
= *children
++;
1297 const uint8_t* s
= children
;
1298 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1299 const char* edgeName
= (char*)s
;
1301 while (*s
!= '\0') {
1302 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1305 cummulativeString
[curStrOffset
+edgeStrLen
] = *s
++;
1306 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1307 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me
-start
), childNodeOffet
, edgeName
);
1308 processExportGraphNode(start
, end
, start
, start
+childNodeOffet
, cummulativeString
, curStrOffset
+edgeStrLen
);
1312 template <typename A
>
1313 void DyldInfoPrinter
<A
>::printExportInfoGraph()
1315 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1316 printf("no compressed export info\n");
1319 const uint8_t* p
= (uint8_t*)fHeader
+ fInfo
->export_off();
1320 const uint8_t* end
= &p
[fInfo
->export_size()];
1321 char cummulativeString
[2000];
1322 printf("digraph {\n");
1323 processExportGraphNode(p
, end
, p
, p
, cummulativeString
, 0);
1328 template <typename A
>
1329 void DyldInfoPrinter
<A
>::gatherNodeStarts(const uint8_t* const start
, const uint8_t* const end
,
1330 const uint8_t* parent
, const uint8_t* p
,
1331 std::vector
<uint32_t>& nodeStarts
)
1333 nodeStarts
.push_back(p
-start
);
1334 const uint8_t terminalSize
= read_uleb128(p
, end
);
1335 const uint8_t* children
= p
+ terminalSize
;
1337 const uint8_t childrenCount
= *children
++;
1338 const uint8_t* s
= children
;
1339 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1340 // skip over edge string
1344 uint32_t childNodeOffet
= read_uleb128(s
, end
);
1345 gatherNodeStarts(start
, end
, start
, start
+childNodeOffet
, nodeStarts
);
1350 template <typename A
>
1351 void DyldInfoPrinter
<A
>::printExportInfoNodes()
1353 if ( (fInfo
== NULL
) || (fInfo
->export_off() == 0) ) {
1354 printf("no compressed export info\n");
1357 const uint8_t* start
= (uint8_t*)fHeader
+ fInfo
->export_off();
1358 const uint8_t* end
= &start
[fInfo
->export_size()];
1359 std::vector
<uint32_t> nodeStarts
;
1360 gatherNodeStarts(start
, end
, start
, start
, nodeStarts
);
1361 std::sort(nodeStarts
.begin(), nodeStarts
.end());
1362 for (std::vector
<uint32_t>::const_iterator it
=nodeStarts
.begin(); it
!= nodeStarts
.end(); ++it
) {
1363 printf("0x%04X: ", *it
);
1364 const uint8_t* p
= start
+ *it
;
1365 uint64_t exportInfoSize
= read_uleb128(p
, end
);
1366 if ( exportInfoSize
!= 0 ) {
1367 // print terminal info
1368 uint64_t flags
= read_uleb128(p
, end
);
1369 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
1370 uint64_t ordinal
= read_uleb128(p
, end
);
1371 const char* importName
= (const char*)p
;
1375 if ( strlen(importName
) == 0 )
1376 printf("[flags=REEXPORT ordinal=%llu] ", ordinal
);
1378 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal
, importName
);
1380 else if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
1381 uint64_t stub
= read_uleb128(p
, end
);
1382 uint64_t resolver
= read_uleb128(p
, end
);
1383 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub
, resolver
);
1386 uint64_t address
= read_uleb128(p
, end
);
1387 if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR
)
1388 printf("[addr=0x%06llX] ", address
);
1389 else if ( (flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
)
1390 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address
);
1392 printf("[flags=0x%llX addr=0x%06llX] ", flags
, address
);
1395 // print child edges
1396 const uint8_t childrenCount
= *p
++;
1397 for (uint8_t i
=0; i
< childrenCount
; ++i
) {
1398 const char* edgeName
= (const char*)p
;
1402 uint32_t childNodeOffet
= read_uleb128(p
, end
);
1403 printf("%s->0x%04X", edgeName
, childNodeOffet
);
1404 if ( i
< (childrenCount
-1) )
1414 template <typename A
>
1415 const uint8_t* DyldInfoPrinter
<A
>::printSharedRegionInfoForEachULEB128Address(const uint8_t* p
, uint8_t kind
)
1417 const char* kindStr
= "??";
1420 kindStr
= "32-bit pointer";
1423 kindStr
= "64-bit pointer";
1426 kindStr
= "ppc hi16";
1429 kindStr
= "32-bit offset to IMPORT";
1432 uint64_t address
= 0;
1437 uint8_t byte
= *p
++;
1438 delta
|= ((byte
& 0x7F) << shift
);
1440 if ( byte
< 0x80 ) {
1443 printf("0x%0llX %s\n", address
+fBaseAddress
, kindStr
);
1455 template <typename A
>
1456 void DyldInfoPrinter
<A
>::printSharedRegionInfo()
1458 if ( (fSharedRegionInfo
== NULL
) || (fSharedRegionInfo
->datasize() == 0) ) {
1459 printf("no shared region info\n");
1462 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fSharedRegionInfo
->dataoff();
1463 const uint8_t* infoEnd
= &infoStart
[fSharedRegionInfo
->datasize()];
1464 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
);) {
1465 uint8_t kind
= *p
++;
1466 p
= this->printSharedRegionInfoForEachULEB128Address(p
, kind
);
1473 void DyldInfoPrinter
<arm
>::printFunctionStartLine(uint64_t addr
)
1476 printf("0x%0llX [thumb] %s\n", (addr
& -2), symbolNameForAddress(addr
& -2));
1478 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1481 template <typename A
>
1482 void DyldInfoPrinter
<A
>::printFunctionStartLine(uint64_t addr
)
1484 printf("0x%0llX %s\n", addr
, symbolNameForAddress(addr
));
1488 template <typename A
>
1489 void DyldInfoPrinter
<A
>::printFunctionStartsInfo()
1491 if ( (fFunctionStartsInfo
== NULL
) || (fFunctionStartsInfo
->datasize() == 0) ) {
1492 printf("no function starts info\n");
1495 const uint8_t* infoStart
= (uint8_t*)fHeader
+ fFunctionStartsInfo
->dataoff();
1496 const uint8_t* infoEnd
= &infoStart
[fFunctionStartsInfo
->datasize()];
1497 uint64_t address
= fBaseAddress
;
1498 for(const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
); ) {
1503 uint8_t byte
= *p
++;
1504 delta
|= ((byte
& 0x7F) << shift
);
1506 if ( byte
< 0x80 ) {
1508 printFunctionStartLine(address
);
1516 template <typename A
>
1517 void DyldInfoPrinter
<A
>::printDylibsInfo()
1519 printf("attributes dependent dylibs\n");
1520 for(typename
std::vector
<const macho_dylib_command
<P
>*>::iterator it
= fDylibLoadCommands
.begin(); it
!= fDylibLoadCommands
.end(); ++it
) {
1521 const macho_dylib_command
<P
>* dylib
= *it
;
1522 const char* attribute
= "";
1523 switch ( dylib
->cmd() ) {
1524 case LC_LOAD_WEAK_DYLIB
:
1525 attribute
= "weak_import";
1527 case LC_REEXPORT_DYLIB
:
1528 attribute
= "re-export";
1530 case LC_LOAD_UPWARD_DYLIB
:
1531 attribute
= "upward";
1533 case LC_LAZY_LOAD_DYLIB
:
1534 attribute
= "lazy_load";
1540 printf(" %-12s %s\n", attribute
, dylib
->name());
1546 ppc::P::uint_t DyldInfoPrinter
<ppc
>::relocBase()
1548 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1549 return fFirstWritableSegment
->vmaddr();
1551 return fFirstSegment
->vmaddr();
1555 ppc64::P::uint_t DyldInfoPrinter
<ppc64
>::relocBase()
1557 if ( fWriteableSegmentWithAddrOver4G
)
1558 return fFirstWritableSegment
->vmaddr();
1560 return fFirstSegment
->vmaddr();
1564 x86::P::uint_t DyldInfoPrinter
<x86
>::relocBase()
1566 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1567 return fFirstWritableSegment
->vmaddr();
1569 return fFirstSegment
->vmaddr();
1573 x86_64::P::uint_t DyldInfoPrinter
<x86_64
>::relocBase()
1575 // check for split-seg
1576 return fFirstWritableSegment
->vmaddr();
1580 arm::P::uint_t DyldInfoPrinter
<arm
>::relocBase()
1582 if ( fHeader
->flags() & MH_SPLIT_SEGS
)
1583 return fFirstWritableSegment
->vmaddr();
1585 return fFirstSegment
->vmaddr();
1590 const char* DyldInfoPrinter
<ppc
>::relocTypeName(uint8_t r_type
)
1592 if ( r_type
== GENERIC_RELOC_VANILLA
)
1594 else if ( r_type
== PPC_RELOC_PB_LA_PTR
)
1595 return "pb pointer";
1601 const char* DyldInfoPrinter
<ppc64
>::relocTypeName(uint8_t r_type
)
1603 if ( r_type
== GENERIC_RELOC_VANILLA
)
1610 const char* DyldInfoPrinter
<x86
>::relocTypeName(uint8_t r_type
)
1612 if ( r_type
== GENERIC_RELOC_VANILLA
)
1614 else if ( r_type
== GENERIC_RELOC_PB_LA_PTR
)
1615 return "pb pointer";
1621 const char* DyldInfoPrinter
<x86_64
>::relocTypeName(uint8_t r_type
)
1623 if ( r_type
== X86_64_RELOC_UNSIGNED
)
1630 const char* DyldInfoPrinter
<arm
>::relocTypeName(uint8_t r_type
)
1632 if ( r_type
== ARM_RELOC_VANILLA
)
1634 else if ( r_type
== ARM_RELOC_PB_LA_PTR
)
1635 return "pb pointer";
1641 template <typename A
>
1642 void DyldInfoPrinter
<A
>::printRelocRebaseInfo()
1644 if ( fDynamicSymbolTable
== NULL
) {
1645 printf("no classic dynamic symbol table");
1648 printf("rebase information (from local relocation records and indirect symbol table):\n");
1649 printf("segment section address type\n");
1650 // walk all local relocations
1651 pint_t rbase
= relocBase();
1652 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->locreloff());
1653 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nlocrel()];
1654 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1655 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
1656 pint_t addr
= reloc
->r_address() + rbase
;
1657 uint8_t segIndex
= segmentIndexForAddress(addr
);
1658 const char* typeName
= relocTypeName(reloc
->r_type());
1659 const char* segName
= segmentName(segIndex
);
1660 const char* sectName
= sectionName(segIndex
, addr
);
1661 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1664 const macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
1665 pint_t addr
= sreloc
->r_address() + rbase
;
1666 uint8_t segIndex
= segmentIndexForAddress(addr
);
1667 const char* typeName
= relocTypeName(sreloc
->r_type());
1668 const char* segName
= segmentName(segIndex
);
1669 const char* sectName
= sectionName(segIndex
, addr
);
1670 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1673 // look for local non-lazy-pointers
1674 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1675 uint8_t segIndex
= 0;
1676 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
, ++segIndex
) {
1677 const macho_segment_command
<P
>* segCmd
= *segit
;
1678 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1679 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1680 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1681 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1682 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
1683 uint32_t indirectOffset
= sect
->reserved1();
1684 uint32_t count
= sect
->size() / sizeof(pint_t
);
1685 for (uint32_t i
=0; i
< count
; ++i
) {
1686 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1687 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
1688 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1689 const char* typeName
= "pointer";
1690 const char* segName
= segmentName(segIndex
);
1691 const char* sectName
= sectionName(segIndex
, addr
);
1692 printf("%-8s %-16s 0x%08llX %s\n", segName
, sectName
, (uint64_t)addr
, typeName
);
1702 template <typename A
>
1703 void DyldInfoPrinter
<A
>::printSymbolTableExportInfo()
1705 if ( fDynamicSymbolTable
== NULL
) {
1706 printf("no classic dynamic symbol table");
1709 printf("export information (from symbol table):\n");
1710 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1711 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1712 const char* flags
= "";
1713 if ( sym
->n_desc() & N_WEAK_DEF
)
1714 flags
= "[weak_def] ";
1716 if ( sym
->n_desc() & N_ARM_THUMB_DEF
)
1718 printf("0x%08llX %s%s\n", sym
->n_value()+thumb
, flags
, &fStrings
[sym
->n_strx()]);
1723 template <typename A
>
1724 const char* DyldInfoPrinter
<A
>::symbolNameForAddress(uint64_t addr
)
1726 // find exact match in globals
1727 const macho_nlist
<P
>* lastExport
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()+fDynamicSymbolTable
->nextdefsym()];
1728 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->iextdefsym()]; sym
< lastExport
; ++sym
) {
1729 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1730 return &fStrings
[sym
->n_strx()];
1733 // find exact match in local symbols
1734 const macho_nlist
<P
>* lastLocal
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()+fDynamicSymbolTable
->nlocalsym()];
1735 for (const macho_nlist
<P
>* sym
= &fSymbols
[fDynamicSymbolTable
->ilocalsym()]; sym
< lastLocal
; ++sym
) {
1736 if ( (sym
->n_value() == addr
) && ((sym
->n_type() & N_TYPE
) == N_SECT
) && ((sym
->n_type() & N_STAB
) == 0) ) {
1737 return &fStrings
[sym
->n_strx()];
1745 template <typename A
>
1746 void DyldInfoPrinter
<A
>::printClassicBindingInfo()
1748 if ( fDynamicSymbolTable
== NULL
) {
1749 printf("no classic dynamic symbol table");
1752 printf("binding information (from relocations and indirect symbol table):\n");
1753 printf("segment section address type weak addend dylib symbol\n");
1754 // walk all external relocations
1755 pint_t rbase
= relocBase();
1756 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->extreloff());
1757 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[fDynamicSymbolTable
->nextrel()];
1758 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1759 pint_t addr
= reloc
->r_address() + rbase
;
1760 uint32_t symbolIndex
= reloc
->r_symbolnum();
1761 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1762 const char* symbolName
= &fStrings
[sym
->n_strx()];
1763 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
1764 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1765 uint8_t segIndex
= segmentIndexForAddress(addr
);
1766 const char* typeName
= relocTypeName(reloc
->r_type());
1767 const char* segName
= segmentName(segIndex
);
1768 const char* sectName
= sectionName(segIndex
, addr
);
1769 const pint_t
* addressMapped
= mappedAddressForVMAddress(addr
);
1770 int64_t addend
= P::getP(*addressMapped
);
1771 if ( fHeader
->flags() & MH_PREBOUND
) {
1772 // In prebound binaries the content is already pointing to the target.
1773 // To get the addend requires subtracting out the base address it was prebound to.
1774 addend
-= sym
->n_value();
1776 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1777 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
1779 // look for non-lazy pointers
1780 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1781 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
1782 const macho_segment_command
<P
>* segCmd
= *segit
;
1783 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1784 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1785 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1786 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1787 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
1788 uint32_t indirectOffset
= sect
->reserved1();
1789 uint32_t count
= sect
->size() / sizeof(pint_t
);
1790 for (uint32_t i
=0; i
< count
; ++i
) {
1791 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1792 if ( symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
1793 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1794 const char* symbolName
= &fStrings
[sym
->n_strx()];
1795 const char* weak_import
= (sym
->n_desc() & N_WEAK_REF
) ? "weak" : "";
1796 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1797 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1798 uint8_t segIndex
= segmentIndexForAddress(addr
);
1799 const char* typeName
= "pointer";
1800 const char* segName
= segmentName(segIndex
);
1801 const char* sectName
= sectionName(segIndex
, addr
);
1803 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName
, sectName
, (uint64_t)addr
,
1804 typeName
, weak_import
, addend
, fromDylib
, symbolName
);
1814 template <typename A
>
1815 void DyldInfoPrinter
<A
>::printClassicLazyBindingInfo()
1817 if ( fDynamicSymbolTable
== NULL
) {
1818 printf("no classic dynamic symbol table");
1821 printf("lazy binding information (from section records and indirect symbol table):\n");
1822 printf("segment section address index dylib symbol\n");
1823 const uint32_t* indirectSymbolTable
= (uint32_t*)(((uint8_t*)fHeader
) + fDynamicSymbolTable
->indirectsymoff());
1824 for(typename
std::vector
<const macho_segment_command
<P
>*>::iterator segit
=fSegments
.begin(); segit
!= fSegments
.end(); ++segit
) {
1825 const macho_segment_command
<P
>* segCmd
= *segit
;
1826 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
1827 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
1828 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1829 uint8_t type
= sect
->flags() & SECTION_TYPE
;
1830 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
1831 uint32_t indirectOffset
= sect
->reserved1();
1832 uint32_t count
= sect
->size() / sizeof(pint_t
);
1833 for (uint32_t i
=0; i
< count
; ++i
) {
1834 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1835 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1836 const char* symbolName
= &fStrings
[sym
->n_strx()];
1837 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1838 pint_t addr
= sect
->addr() + i
*sizeof(pint_t
);
1839 uint8_t segIndex
= segmentIndexForAddress(addr
);
1840 const char* segName
= segmentName(segIndex
);
1841 const char* sectName
= sectionName(segIndex
, addr
);
1842 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
1845 else if ( (type
== S_SYMBOL_STUBS
) && (((sect
->flags() & S_ATTR_SELF_MODIFYING_CODE
) != 0)) && (sect
->reserved2() == 5) ) {
1846 // i386 self-modifying stubs
1847 uint32_t indirectOffset
= sect
->reserved1();
1848 uint32_t count
= sect
->size() / 5;
1849 for (uint32_t i
=0; i
< count
; ++i
) {
1850 uint32_t symbolIndex
= E::get32(indirectSymbolTable
[indirectOffset
+i
]);
1851 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
1852 const macho_nlist
<P
>* sym
= &fSymbols
[symbolIndex
];
1853 const char* symbolName
= &fStrings
[sym
->n_strx()];
1854 const char* fromDylib
= classicOrdinalName(GET_LIBRARY_ORDINAL(sym
->n_desc()));
1855 pint_t addr
= sect
->addr() + i
*5;
1856 uint8_t segIndex
= segmentIndexForAddress(addr
);
1857 const char* segName
= segmentName(segIndex
);
1858 const char* sectName
= sectionName(segIndex
, addr
);
1859 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName
, sectName
, (uint64_t)addr
, symbolIndex
, fromDylib
, symbolName
);
1868 static void dump(const char* path
)
1870 struct stat stat_buf
;
1873 int fd
= ::open(path
, O_RDONLY
, 0);
1875 throw "cannot open file";
1876 if ( ::fstat(fd
, &stat_buf
) != 0 )
1877 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
1878 uint32_t length
= stat_buf
.st_size
;
1879 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1880 if ( p
== ((uint8_t*)(-1)) )
1881 throw "cannot map file";
1883 const mach_header
* mh
= (mach_header
*)p
;
1884 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1885 const struct fat_header
* fh
= (struct fat_header
*)p
;
1886 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1887 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1888 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1889 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
1890 cpu_type_t cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
1891 cpu_type_t cpusubtype
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
);
1892 if ( (cputype
== sPreferredArch
)
1893 && ((sPreferredSubArch
==0) || (sPreferredSubArch
==cpusubtype
)) ) {
1895 case CPU_TYPE_POWERPC
:
1896 if ( DyldInfoPrinter
<ppc
>::validFile(p
+ offset
) )
1897 DyldInfoPrinter
<ppc
>::make(p
+ offset
, size
, path
);
1899 throw "in universal file, ppc slice does not contain ppc mach-o";
1902 if ( DyldInfoPrinter
<x86
>::validFile(p
+ offset
) )
1903 DyldInfoPrinter
<x86
>::make(p
+ offset
, size
, path
);
1905 throw "in universal file, i386 slice does not contain i386 mach-o";
1907 case CPU_TYPE_POWERPC64
:
1908 if ( DyldInfoPrinter
<ppc64
>::validFile(p
+ offset
) )
1909 DyldInfoPrinter
<ppc64
>::make(p
+ offset
, size
, path
);
1911 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
1913 case CPU_TYPE_X86_64
:
1914 if ( DyldInfoPrinter
<x86_64
>::validFile(p
+ offset
) )
1915 DyldInfoPrinter
<x86_64
>::make(p
+ offset
, size
, path
);
1917 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
1920 if ( DyldInfoPrinter
<arm
>::validFile(p
+ offset
) )
1921 DyldInfoPrinter
<arm
>::make(p
+ offset
, size
, path
);
1923 throw "in universal file, arm slice does not contain arm mach-o";
1926 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
1931 else if ( DyldInfoPrinter
<x86
>::validFile(p
) ) {
1932 DyldInfoPrinter
<x86
>::make(p
, length
, path
);
1934 else if ( DyldInfoPrinter
<ppc
>::validFile(p
) ) {
1935 DyldInfoPrinter
<ppc
>::make(p
, length
, path
);
1937 else if ( DyldInfoPrinter
<ppc64
>::validFile(p
) ) {
1938 DyldInfoPrinter
<ppc64
>::make(p
, length
, path
);
1940 else if ( DyldInfoPrinter
<x86_64
>::validFile(p
) ) {
1941 DyldInfoPrinter
<x86_64
>::make(p
, length
, path
);
1943 else if ( DyldInfoPrinter
<arm
>::validFile(p
) ) {
1944 DyldInfoPrinter
<arm
>::make(p
, length
, path
);
1947 throw "not a known file type";
1950 catch (const char* msg
) {
1951 throwf("%s in %s", msg
, path
);
1957 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
1958 "\t-dylibs print dependent dylibs\n"
1959 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
1960 "\t-bind print addresses dyld will set based on symbolic lookups\n"
1961 "\t-weak_bind print symbols which dyld must coalesce\n"
1962 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
1963 "\t-export print addresses of all symbols this file exports\n"
1964 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
1965 "\t-function_starts print table of function start addresses\n"
1966 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
1971 int main(int argc
, const char* argv
[])
1979 std::vector
<const char*> files
;
1980 for(int i
=1; i
< argc
; ++i
) {
1981 const char* arg
= argv
[i
];
1982 if ( arg
[0] == '-' ) {
1983 if ( strcmp(arg
, "-arch") == 0 ) {
1984 const char* arch
= ++i
<argc
? argv
[i
]: "";
1985 if ( strcmp(arch
, "ppc64") == 0 )
1986 sPreferredArch
= CPU_TYPE_POWERPC64
;
1987 else if ( strcmp(arch
, "ppc") == 0 )
1988 sPreferredArch
= CPU_TYPE_POWERPC
;
1989 else if ( strcmp(arch
, "i386") == 0 )
1990 sPreferredArch
= CPU_TYPE_I386
;
1991 else if ( strcmp(arch
, "x86_64") == 0 )
1992 sPreferredArch
= CPU_TYPE_X86_64
;
1993 else if ( strcmp(arch
, "arm") == 0 )
1994 sPreferredArch
= CPU_TYPE_ARM
;
1995 else if ( strcmp(arch
, "armv4t") == 0 ) {
1996 sPreferredArch
= CPU_TYPE_ARM
;
1997 sPreferredSubArch
= CPU_SUBTYPE_ARM_V4T
;
1999 else if ( strcmp(arch
, "armv5") == 0 ) {
2000 sPreferredArch
= CPU_TYPE_ARM
;
2001 sPreferredSubArch
= CPU_SUBTYPE_ARM_V5TEJ
;
2003 else if ( strcmp(arch
, "armv6") == 0 ) {
2004 sPreferredArch
= CPU_TYPE_ARM
;
2005 sPreferredSubArch
= CPU_SUBTYPE_ARM_V6
;
2007 else if ( strcmp(arch
, "armv7") == 0 ) {
2008 sPreferredArch
= CPU_TYPE_ARM
;
2009 sPreferredSubArch
= CPU_SUBTYPE_ARM_V7
;
2012 throwf("unknown architecture %s", arch
);
2014 else if ( strcmp(arg
, "-rebase") == 0 ) {
2017 else if ( strcmp(arg
, "-bind") == 0 ) {
2020 else if ( strcmp(arg
, "-weak_bind") == 0 ) {
2021 printWeakBind
= true;
2023 else if ( strcmp(arg
, "-lazy_bind") == 0 ) {
2024 printLazyBind
= true;
2026 else if ( strcmp(arg
, "-export") == 0 ) {
2029 else if ( strcmp(arg
, "-opcodes") == 0 ) {
2030 printOpcodes
= true;
2032 else if ( strcmp(arg
, "-export_dot") == 0 ) {
2033 printExportGraph
= true;
2035 else if ( strcmp(arg
, "-export_trie_nodes") == 0 ) {
2036 printExportNodes
= true;
2038 else if ( strcmp(arg
, "-shared_region") == 0 ) {
2039 printSharedRegion
= true;
2041 else if ( strcmp(arg
, "-function_starts") == 0 ) {
2042 printFunctionStarts
= true;
2044 else if ( strcmp(arg
, "-dylibs") == 0 ) {
2048 throwf("unknown option: %s\n", arg
);
2052 files
.push_back(arg
);
2055 if ( files
.size() == 0 )
2057 if ( files
.size() == 1 ) {
2061 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
2062 printf("\n%s:\n", *it
);
2067 catch (const char* msg
) {
2068 fprintf(stderr
, "dyldinfo failed: %s\n", msg
);