Version and Help output changes. - Add --target-help/--help and a BUGURL - Add GNU...
[darwin-xtools.git] / ld64 / src / other / dyldinfo.cpp
blob2d69fcd66b85e8d9df7d7bd4b58e9c80ec28eb3d
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@
6 *
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
12 * file.
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>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <errno.h>
34 #include <vector>
35 #include <set>
36 #include <unordered_set>
38 #include "configure.h"
39 #include "MachOFileAbstraction.hpp"
40 #include "Architectures.hpp"
41 #include "MachOTrie.hpp"
42 #include "../ld/code-sign-blobs/superblob.h"
44 static bool printRebase = false;
45 static bool printBind = false;
46 static bool printWeakBind = false;
47 static bool printLazyBind = false;
48 static bool printOpcodes = false;
49 static bool printExport = false;
50 static bool printExportGraph = false;
51 static bool printExportNodes = false;
52 static bool printSharedRegion = false;
53 static bool printFunctionStarts = false;
54 static bool printDylibs = false;
55 static bool printDRs = false;
56 static bool printDataCode = false;
57 static cpu_type_t sPreferredArch = 0;
58 static cpu_type_t sPreferredSubArch = 0;
61 __attribute__((noreturn))
62 static void throwf(const char* format, ...)
64 va_list list;
65 char* p;
66 va_start(list, format);
67 vasprintf(&p, format, list);
68 va_end(list);
70 const char* t = p;
71 throw t;
75 template <typename A>
76 class DyldInfoPrinter
78 public:
79 static bool validFile(const uint8_t* fileContent);
80 static DyldInfoPrinter<A>* make(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
81 { return new DyldInfoPrinter<A>(fileContent, fileLength, path, printArch); }
82 virtual ~DyldInfoPrinter() {}
85 private:
86 typedef typename A::P P;
87 typedef typename A::P::E E;
88 typedef typename A::P::uint_t pint_t;
90 DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch);
91 void printRebaseInfo();
92 void printRebaseInfoOpcodes();
93 void printBindingInfo();
94 void printWeakBindingInfo();
95 void printLazyBindingInfo();
96 void printBindingInfoOpcodes(bool weakBinding);
97 void printWeakBindingInfoOpcodes();
98 void printLazyBindingOpcodes();
99 void printExportInfo();
100 void printExportInfoGraph();
101 void printExportInfoNodes();
102 void printRelocRebaseInfo();
103 void printSymbolTableExportInfo();
104 void printClassicLazyBindingInfo();
105 void printClassicBindingInfo();
106 void printSharedRegionInfo();
107 const char* sharedRegionKindName(uint8_t kind);
108 void printFunctionStartsInfo();
109 void printDylibsInfo();
110 void printDRInfo();
111 void printDataInCode();
112 void printFunctionStartLine(uint64_t addr);
113 const uint8_t* printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end, uint8_t kind);
114 const uint8_t* printSharedRegionV2InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end);
115 const uint8_t* printSharedRegionV2InfoForEachULEB128AddressAndAdj(const uint8_t* p, const uint8_t* end);
116 const uint8_t* printSharedRegionV2SectionPair(const uint8_t* p, const uint8_t* end);
117 const uint8_t* printSharedRegionV2ToSectionOffset(const uint8_t* p, const uint8_t* end);
118 const uint8_t* printSharedRegionV2Kind(const uint8_t* p, const uint8_t* end);
120 pint_t relocBase();
121 const char* relocTypeName(uint8_t r_type);
122 uint8_t segmentIndexForAddress(pint_t addr);
123 void processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
124 const uint8_t* parent, const uint8_t* p,
125 char* cummulativeString, int curStrOffset);
126 void gatherNodeStarts(const uint8_t* const start, const uint8_t* const end,
127 const uint8_t* parent, const uint8_t* p,
128 std::vector<uint32_t>& nodeStarts);
129 const char* rebaseTypeName(uint8_t type);
130 const char* bindTypeName(uint8_t type);
131 pint_t segStartAddress(uint8_t segIndex);
132 const char* segmentName(uint8_t segIndex);
133 const char* sectionName(uint8_t segIndex, pint_t address);
134 const char* getSegAndSectName(uint8_t segIndex, pint_t address);
135 const char* ordinalName(int libraryOrdinal);
136 const char* classicOrdinalName(int libraryOrdinal);
137 pint_t* mappedAddressForVMAddress(pint_t vmaddress);
138 const char* symbolNameForAddress(uint64_t);
139 const char* closestSymbolNameForAddress(uint64_t addr, uint64_t* offset, uint8_t sectIndex=0);
142 const char* fPath;
143 const macho_header<P>* fHeader;
144 uint64_t fLength;
145 const char* fStrings;
146 const char* fStringsEnd;
147 const macho_nlist<P>* fSymbols;
148 uint32_t fSymbolCount;
149 const macho_dyld_info_command<P>* fInfo;
150 const macho_linkedit_data_command<P>* fSharedRegionInfo;
151 const macho_linkedit_data_command<P>* fFunctionStartsInfo;
152 const macho_linkedit_data_command<P>* fDataInCode;
153 const macho_linkedit_data_command<P>* fDRInfo;
154 uint64_t fBaseAddress;
155 const macho_dysymtab_command<P>* fDynamicSymbolTable;
156 const macho_segment_command<P>* fFirstSegment;
157 const macho_segment_command<P>* fFirstWritableSegment;
158 bool fWriteableSegmentWithAddrOver4G;
159 std::vector<const macho_segment_command<P>*>fSegments;
160 std::vector<const macho_section<P>*> fSections;
161 std::vector<const char*> fDylibs;
162 std::vector<const macho_dylib_command<P>*> fDylibLoadCommands;
163 macho_section<P> fMachHeaderPseudoSection;
168 template <>
169 bool DyldInfoPrinter<ppc>::validFile(const uint8_t* fileContent)
171 const macho_header<P>* header = (const macho_header<P>*)fileContent;
172 if ( header->magic() != MH_MAGIC )
173 return false;
174 if ( header->cputype() != CPU_TYPE_POWERPC )
175 return false;
176 switch (header->filetype()) {
177 case MH_EXECUTE:
178 case MH_DYLIB:
179 case MH_DYLIB_STUB:
180 case MH_BUNDLE:
181 case MH_DYLINKER:
182 return true;
184 return false;
187 template <>
188 bool DyldInfoPrinter<ppc64>::validFile(const uint8_t* fileContent)
190 const macho_header<P>* header = (const macho_header<P>*)fileContent;
191 if ( header->magic() != MH_MAGIC_64 )
192 return false;
193 if ( header->cputype() != CPU_TYPE_POWERPC64 )
194 return false;
195 switch (header->filetype()) {
196 case MH_EXECUTE:
197 case MH_DYLIB:
198 case MH_DYLIB_STUB:
199 case MH_BUNDLE:
200 case MH_DYLINKER:
201 return true;
203 return false;
206 template <>
207 bool DyldInfoPrinter<x86>::validFile(const uint8_t* fileContent)
209 const macho_header<P>* header = (const macho_header<P>*)fileContent;
210 if ( header->magic() != MH_MAGIC )
211 return false;
212 if ( header->cputype() != CPU_TYPE_I386 )
213 return false;
214 switch (header->filetype()) {
215 case MH_EXECUTE:
216 case MH_DYLIB:
217 case MH_DYLIB_STUB:
218 case MH_BUNDLE:
219 case MH_DYLINKER:
220 return true;
222 return false;
225 template <>
226 bool DyldInfoPrinter<x86_64>::validFile(const uint8_t* fileContent)
228 const macho_header<P>* header = (const macho_header<P>*)fileContent;
229 if ( header->magic() != MH_MAGIC_64 )
230 return false;
231 if ( header->cputype() != CPU_TYPE_X86_64 )
232 return false;
233 switch (header->filetype()) {
234 case MH_EXECUTE:
235 case MH_DYLIB:
236 case MH_DYLIB_STUB:
237 case MH_BUNDLE:
238 case MH_DYLINKER:
239 case MH_KEXT_BUNDLE:
240 return true;
242 return false;
245 #if SUPPORT_ARCH_arm_any
246 template <>
247 bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
249 const macho_header<P>* header = (const macho_header<P>*)fileContent;
250 if ( header->magic() != MH_MAGIC )
251 return false;
252 if ( header->cputype() != CPU_TYPE_ARM )
253 return false;
254 switch (header->filetype()) {
255 case MH_EXECUTE:
256 case MH_DYLIB:
257 case MH_DYLIB_STUB:
258 case MH_BUNDLE:
259 case MH_DYLINKER:
260 case MH_KEXT_BUNDLE:
261 return true;
263 return false;
265 #endif
267 #if SUPPORT_ARCH_arm64
268 template <>
269 bool DyldInfoPrinter<arm64>::validFile(const uint8_t* fileContent)
271 const macho_header<P>* header = (const macho_header<P>*)fileContent;
272 if ( header->magic() != MH_MAGIC_64 )
273 return false;
274 if ( header->cputype() != CPU_TYPE_ARM64 )
275 return false;
276 switch (header->filetype()) {
277 case MH_EXECUTE:
278 case MH_DYLIB:
279 case MH_BUNDLE:
280 case MH_DYLINKER:
281 case MH_KEXT_BUNDLE:
282 return true;
284 return false;
286 #endif
289 template <typename A>
290 DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
291 : fHeader(NULL), fLength(fileLength),
292 fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL),
293 fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), fDataInCode(NULL), fDRInfo(NULL),
294 fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL),
295 fWriteableSegmentWithAddrOver4G(false)
297 // sanity check
298 if ( ! validFile(fileContent) )
299 throw "not a mach-o file that can be checked";
301 fPath = strdup(path);
302 fHeader = (const macho_header<P>*)fileContent;
304 fMachHeaderPseudoSection.set_segname("__TEXT");
305 fMachHeaderPseudoSection.set_sectname("");
306 fMachHeaderPseudoSection.set_addr(0);
307 fSections.push_back(&fMachHeaderPseudoSection);
309 // get LC_DYLD_INFO
310 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
311 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
312 const uint32_t cmd_count = fHeader->ncmds();
313 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
314 const macho_load_command<P>* cmd = cmds;
315 for (uint32_t i = 0; i < cmd_count; ++i) {
316 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
317 if ( endOfCmd > endOfLoadCommands )
318 throwf("load command #%d extends beyond the end of the load commands", i);
319 if ( endOfCmd > endOfFile )
320 throwf("load command #%d extends beyond the end of the file", i);
321 switch ( cmd->cmd() ) {
322 case LC_DYLD_INFO:
323 case LC_DYLD_INFO_ONLY:
324 fInfo = (macho_dyld_info_command<P>*)cmd;
325 break;
326 case macho_segment_command<P>::CMD:
328 const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
329 fSegments.push_back(segCmd);
330 if ( (segCmd->fileoff() == 0) && (segCmd->filesize() != 0) )
331 fBaseAddress = segCmd->vmaddr();
332 if ( fFirstSegment == NULL )
333 fFirstSegment = segCmd;
334 if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) {
335 if ( fFirstWritableSegment == NULL )
336 fFirstWritableSegment = segCmd;
337 if ( segCmd->vmaddr() > 0x100000000ULL )
338 fWriteableSegmentWithAddrOver4G = true;
340 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
341 const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
342 for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect)
343 fSections.push_back(sect);
345 break;
346 case LC_LOAD_DYLIB:
347 case LC_LOAD_WEAK_DYLIB:
348 case LC_REEXPORT_DYLIB:
349 case LC_LOAD_UPWARD_DYLIB:
350 case LC_LAZY_LOAD_DYLIB:
352 const macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
353 fDylibLoadCommands.push_back(dylib);
354 const char* lastSlash = strrchr(dylib->name(), '/');
355 const char* leafName = (lastSlash != NULL) ? lastSlash+1 : dylib->name();
356 const char* firstDot = strchr(leafName, '.');
357 if ( firstDot != NULL ) {
358 char* t = strdup(leafName);
359 t[firstDot-leafName] = '\0';
360 fDylibs.push_back(t);
362 else {
363 fDylibs.push_back(leafName);
366 break;
367 case LC_DYSYMTAB:
368 fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
369 break;
370 case LC_SYMTAB:
372 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
373 fSymbolCount = symtab->nsyms();
374 fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
375 fStrings = (char*)fHeader + symtab->stroff();
376 fStringsEnd = fStrings + symtab->strsize();
378 break;
379 case LC_SEGMENT_SPLIT_INFO:
380 fSharedRegionInfo = (macho_linkedit_data_command<P>*)cmd;
381 break;
382 case LC_FUNCTION_STARTS:
383 fFunctionStartsInfo = (macho_linkedit_data_command<P>*)cmd;
384 break;
385 case LC_DATA_IN_CODE:
386 fDataInCode = (macho_linkedit_data_command<P>*)cmd;
387 break;
388 case LC_DYLIB_CODE_SIGN_DRS:
389 fDRInfo = (macho_linkedit_data_command<P>*)cmd;
390 break;
392 cmd = (const macho_load_command<P>*)endOfCmd;
395 if ( printArch ) {
396 for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
397 if ( (cpu_type_t)fHeader->cputype() == t->cpuType ) {
398 if ( t->isSubType && ((cpu_subtype_t)fHeader->cpusubtype() != t->cpuSubType) )
399 continue;
400 printf("for arch %s:\n", t->archName);
405 if ( printRebase ) {
406 if ( fInfo != NULL )
407 printRebaseInfo();
408 else
409 printRelocRebaseInfo();
411 if ( printBind ) {
412 if ( fInfo != NULL )
413 printBindingInfo();
414 else
415 printClassicBindingInfo();
417 if ( printWeakBind )
418 printWeakBindingInfo();
419 if ( printLazyBind ) {
420 if ( fInfo != NULL )
421 printLazyBindingInfo();
422 else
423 printClassicLazyBindingInfo();
425 if ( printExport ) {
426 if ( fInfo != NULL )
427 printExportInfo();
428 else
429 printSymbolTableExportInfo();
431 if ( printOpcodes ) {
432 printRebaseInfoOpcodes();
433 printBindingInfoOpcodes(false);
434 printBindingInfoOpcodes(true);
435 printLazyBindingOpcodes();
437 if ( printExportGraph )
438 printExportInfoGraph();
439 if ( printExportNodes )
440 printExportInfoNodes();
441 if ( printSharedRegion )
442 printSharedRegionInfo();
443 if ( printFunctionStarts )
444 printFunctionStartsInfo();
445 if ( printDylibs )
446 printDylibsInfo();
447 if ( printDRs )
448 printDRInfo();
449 if ( printDataCode )
450 printDataInCode();
453 static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
455 uint64_t result = 0;
456 int bit = 0;
457 do {
458 if (p == end)
459 throwf("malformed uleb128");
461 uint64_t slice = *p & 0x7f;
463 if (bit >= 64 || slice << bit >> bit != slice)
464 throwf("uleb128 too big");
465 else {
466 result |= (slice << bit);
467 bit += 7;
470 while (*p++ & 0x80);
471 return result;
474 static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
476 int64_t result = 0;
477 int bit = 0;
478 uint8_t byte;
479 do {
480 if (p == end)
481 throwf("malformed sleb128");
482 byte = *p++;
483 result |= (((int64_t)(byte & 0x7f)) << bit);
484 bit += 7;
485 } while (byte & 0x80);
486 // sign extend negative numbers
487 if ( (byte & 0x40) != 0 )
488 result |= (-1LL) << bit;
489 return result;
493 template <typename A>
494 const char* DyldInfoPrinter<A>::rebaseTypeName(uint8_t type)
496 switch (type ){
497 case REBASE_TYPE_POINTER:
498 return "pointer";
499 case REBASE_TYPE_TEXT_ABSOLUTE32:
500 return "text abs32";
501 case REBASE_TYPE_TEXT_PCREL32:
502 return "text rel32";
504 return "!!unknown!!";
508 template <typename A>
509 const char* DyldInfoPrinter<A>::bindTypeName(uint8_t type)
511 switch (type ){
512 case BIND_TYPE_POINTER:
513 return "pointer";
514 case BIND_TYPE_TEXT_ABSOLUTE32:
515 return "text abs32";
516 case BIND_TYPE_TEXT_PCREL32:
517 return "text rel32";
519 return "!!unknown!!";
523 template <typename A>
524 typename A::P::uint_t DyldInfoPrinter<A>::segStartAddress(uint8_t segIndex)
526 if ( segIndex > fSegments.size() )
527 throw "segment index out of range";
528 return fSegments[segIndex]->vmaddr();
531 template <typename A>
532 const char* DyldInfoPrinter<A>::segmentName(uint8_t segIndex)
534 if ( segIndex > fSegments.size() )
535 throw "segment index out of range";
536 return fSegments[segIndex]->segname();
539 template <typename A>
540 const char* DyldInfoPrinter<A>::sectionName(uint8_t segIndex, pint_t address)
542 if ( segIndex > fSegments.size() )
543 throw "segment index out of range";
544 const macho_segment_command<P>* segCmd = fSegments[segIndex];
545 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
546 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
547 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
548 if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
549 if ( strlen(sect->sectname()) > 15 ) {
550 static char temp[18];
551 strlcpy(temp, sect->sectname(), 17);
552 return temp;
554 else {
555 return sect->sectname();
559 return "??";
562 template <typename A>
563 const char* DyldInfoPrinter<A>::getSegAndSectName(uint8_t segIndex, pint_t address)
565 static char buffer[64];
566 strcpy(buffer, segmentName(segIndex));
567 strcat(buffer, "/");
568 const macho_segment_command<P>* segCmd = fSegments[segIndex];
569 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
570 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
571 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
572 if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
573 // section name may not be zero terminated
574 char* end = &buffer[strlen(buffer)];
575 strlcpy(end, sect->sectname(), 16);
576 return buffer;
579 return "??";
582 template <typename A>
583 uint8_t DyldInfoPrinter<A>::segmentIndexForAddress(pint_t address)
585 for(unsigned int i=0; i < fSegments.size(); ++i) {
586 if ( (fSegments[i]->vmaddr() <= address) && (address < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) {
587 return i;
590 throwf("address 0x%llX is not in any segment", (uint64_t)address);
593 template <typename A>
594 typename A::P::uint_t* DyldInfoPrinter<A>::mappedAddressForVMAddress(pint_t vmaddress)
596 for(unsigned int i=0; i < fSegments.size(); ++i) {
597 if ( (fSegments[i]->vmaddr() <= vmaddress) && (vmaddress < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) {
598 unsigned long offsetInMappedFile = fSegments[i]->fileoff()+vmaddress-fSegments[i]->vmaddr();
599 return (pint_t*)((uint8_t*)fHeader + offsetInMappedFile);
602 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress);
605 template <typename A>
606 const char* DyldInfoPrinter<A>::ordinalName(int libraryOrdinal)
608 switch ( libraryOrdinal) {
609 case BIND_SPECIAL_DYLIB_SELF:
610 return "this-image";
611 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
612 return "main-executable";
613 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
614 return "flat-namespace";
616 if ( libraryOrdinal < BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
617 throw "unknown special ordinal";
618 if ( libraryOrdinal > (int)fDylibs.size() )
619 throw "libraryOrdinal out of range";
620 return fDylibs[libraryOrdinal-1];
623 template <typename A>
624 const char* DyldInfoPrinter<A>::classicOrdinalName(int libraryOrdinal)
626 if ( (fHeader->flags() & MH_TWOLEVEL) == 0 )
627 return "flat-namespace";
628 switch ( libraryOrdinal) {
629 case SELF_LIBRARY_ORDINAL:
630 return "this-image";
631 case EXECUTABLE_ORDINAL:
632 return "main-executable";
633 case DYNAMIC_LOOKUP_ORDINAL:
634 return "flat-namespace";
636 if ( libraryOrdinal > (int)fDylibs.size() )
637 throw "libraryOrdinal out of range";
638 return fDylibs[libraryOrdinal-1];
641 template <typename A>
642 void DyldInfoPrinter<A>::printRebaseInfo()
644 if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
645 printf("no compressed rebase info\n");
647 else {
648 printf("rebase information (from compressed dyld info):\n");
649 printf("segment section address type\n");
651 const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
652 const uint8_t* end = &p[fInfo->rebase_size()];
654 uint8_t type = 0;
655 uint64_t segOffset = 0;
656 uint32_t count;
657 uint32_t skip;
658 int segIndex = 0;
659 pint_t segStartAddr = 0;
660 const char* segName = "??";
661 const char* typeName = "??";
662 bool done = false;
663 while ( !done && (p < end) ) {
664 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
665 uint8_t opcode = *p & REBASE_OPCODE_MASK;
666 ++p;
667 switch (opcode) {
668 case REBASE_OPCODE_DONE:
669 done = true;
670 break;
671 case REBASE_OPCODE_SET_TYPE_IMM:
672 type = immediate;
673 typeName = rebaseTypeName(type);
674 break;
675 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
676 segIndex = immediate;
677 segStartAddr = segStartAddress(segIndex);
678 segName = segmentName(segIndex);
679 segOffset = read_uleb128(p, end);
680 break;
681 case REBASE_OPCODE_ADD_ADDR_ULEB:
682 segOffset += read_uleb128(p, end);
683 break;
684 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
685 segOffset += immediate*sizeof(pint_t);
686 break;
687 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
688 for (int i=0; i < immediate; ++i) {
689 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
690 segOffset += sizeof(pint_t);
692 break;
693 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
694 count = read_uleb128(p, end);
695 for (uint32_t i=0; i < count; ++i) {
696 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
697 segOffset += sizeof(pint_t);
699 break;
700 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
701 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
702 segOffset += read_uleb128(p, end) + sizeof(pint_t);
703 break;
704 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
705 count = read_uleb128(p, end);
706 skip = read_uleb128(p, end);
707 for (uint32_t i=0; i < count; ++i) {
708 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
709 segOffset += skip + sizeof(pint_t);
711 break;
712 default:
713 throwf("bad rebase opcode %d", *p);
722 template <typename A>
723 void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
725 if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
726 printf("no compressed rebase info\n");
728 else {
729 printf("rebase opcodes:\n");
730 const uint8_t* start = (uint8_t*)fHeader + fInfo->rebase_off();
731 const uint8_t* end = &start[fInfo->rebase_size()];
732 const uint8_t* p = start;
734 uint8_t type = 0;
735 uint64_t address = fBaseAddress;
736 uint32_t count;
737 uint32_t skip;
738 unsigned int segmentIndex;
739 bool done = false;
740 while ( !done && (p < end) ) {
741 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
742 uint8_t opcode = *p & REBASE_OPCODE_MASK;
743 uint32_t opcodeOffset = p-start;
744 ++p;
745 switch (opcode) {
746 case REBASE_OPCODE_DONE:
747 done = true;
748 printf("0x%04X REBASE_OPCODE_DONE()\n", opcodeOffset);
749 break;
750 case REBASE_OPCODE_SET_TYPE_IMM:
751 type = immediate;
752 printf("0x%04X REBASE_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
753 break;
754 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
755 segmentIndex = immediate;
756 address = read_uleb128(p, end);
757 printf("0x%04X REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
758 break;
759 case REBASE_OPCODE_ADD_ADDR_ULEB:
760 address = read_uleb128(p, end);
761 printf("0x%04X REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", opcodeOffset, address);
762 break;
763 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
764 address = immediate*sizeof(pint_t);
765 printf("0x%04X REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", opcodeOffset, address);
766 break;
767 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
768 printf("0x%04X REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", opcodeOffset, immediate);
769 break;
770 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
771 count = read_uleb128(p, end);
772 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", opcodeOffset, count);
773 break;
774 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
775 skip = read_uleb128(p, end) + sizeof(pint_t);
776 printf("0x%04X REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", opcodeOffset, skip);
777 break;
778 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
779 count = read_uleb128(p, end);
780 skip = read_uleb128(p, end);
781 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", opcodeOffset, count, skip);
782 break;
783 default:
784 throwf("bad rebase opcode %d", *p);
796 template <typename A>
797 void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
799 if ( fInfo == NULL ) {
800 printf("no compressed binding info\n");
802 else if ( !weakbinding && (fInfo->bind_off() == 0) ) {
803 printf("no compressed binding info\n");
805 else if ( weakbinding && (fInfo->weak_bind_off() == 0) ) {
806 printf("no compressed weak binding info\n");
808 else {
809 const uint8_t* start;
810 const uint8_t* end;
811 if ( weakbinding ) {
812 printf("weak binding opcodes:\n");
813 start = (uint8_t*)fHeader + fInfo->weak_bind_off();
814 end = &start[fInfo->weak_bind_size()];
816 else {
817 printf("binding opcodes:\n");
818 start = (uint8_t*)fHeader + fInfo->bind_off();
819 end = &start[fInfo->bind_size()];
821 const uint8_t* p = start;
822 uint8_t type = 0;
823 uint8_t flags;
824 uint64_t address = fBaseAddress;
825 const char* symbolName = NULL;
826 int libraryOrdinal = 0;
827 int64_t addend = 0;
828 uint32_t segmentIndex = 0;
829 uint32_t count;
830 uint32_t skip;
831 bool done = false;
832 while ( !done && (p < end) ) {
833 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
834 uint8_t opcode = *p & BIND_OPCODE_MASK;
835 uint32_t opcodeOffset = p-start;
836 ++p;
837 switch (opcode) {
838 case BIND_OPCODE_DONE:
839 done = true;
840 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
841 break;
842 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
843 libraryOrdinal = immediate;
844 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
845 break;
846 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
847 libraryOrdinal = read_uleb128(p, end);
848 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
849 break;
850 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
851 // the special ordinals are negative numbers
852 if ( immediate == 0 )
853 libraryOrdinal = 0;
854 else {
855 int8_t signExtended = BIND_OPCODE_MASK | immediate;
856 libraryOrdinal = signExtended;
858 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
859 break;
860 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
861 flags = immediate;
862 symbolName = (char*)p;
863 while (*p != '\0')
864 ++p;
865 ++p;
866 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
867 break;
868 case BIND_OPCODE_SET_TYPE_IMM:
869 type = immediate;
870 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
871 break;
872 case BIND_OPCODE_SET_ADDEND_SLEB:
873 addend = read_sleb128(p, end);
874 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
875 break;
876 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
877 segmentIndex = immediate;
878 address = read_uleb128(p, end);
879 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
880 break;
881 case BIND_OPCODE_ADD_ADDR_ULEB:
882 skip = read_uleb128(p, end);
883 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
884 break;
885 case BIND_OPCODE_DO_BIND:
886 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
887 break;
888 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
889 skip = read_uleb128(p, end);
890 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
891 break;
892 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
893 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
894 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
895 break;
896 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
897 count = read_uleb128(p, end);
898 skip = read_uleb128(p, end);
899 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
900 break;
901 default:
902 throwf("unknown bind opcode %d", *p);
911 template <typename A>
912 void DyldInfoPrinter<A>::printBindingInfo()
914 if ( (fInfo == NULL) || (fInfo->bind_off() == 0) ) {
915 printf("no compressed binding info\n");
917 else {
918 printf("bind information:\n");
919 printf("segment section address type addend dylib symbol\n");
920 const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
921 const uint8_t* end = &p[fInfo->bind_size()];
923 uint8_t type = 0;
924 uint8_t segIndex = 0;
925 uint64_t segOffset = 0;
926 const char* symbolName = NULL;
927 const char* fromDylib = "??";
928 int libraryOrdinal = 0;
929 int64_t addend = 0;
930 uint32_t count;
931 uint32_t skip;
932 pint_t segStartAddr = 0;
933 const char* segName = "??";
934 const char* typeName = "??";
935 const char* weak_import = "";
936 bool done = false;
937 while ( !done && (p < end) ) {
938 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
939 uint8_t opcode = *p & BIND_OPCODE_MASK;
940 ++p;
941 switch (opcode) {
942 case BIND_OPCODE_DONE:
943 done = true;
944 break;
945 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
946 libraryOrdinal = immediate;
947 fromDylib = ordinalName(libraryOrdinal);
948 break;
949 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
950 libraryOrdinal = read_uleb128(p, end);
951 fromDylib = ordinalName(libraryOrdinal);
952 break;
953 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
954 // the special ordinals are negative numbers
955 if ( immediate == 0 )
956 libraryOrdinal = 0;
957 else {
958 int8_t signExtended = BIND_OPCODE_MASK | immediate;
959 libraryOrdinal = signExtended;
961 fromDylib = ordinalName(libraryOrdinal);
962 break;
963 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
964 symbolName = (char*)p;
965 while (*p != '\0')
966 ++p;
967 ++p;
968 if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
969 weak_import = " (weak import)";
970 else
971 weak_import = "";
972 break;
973 case BIND_OPCODE_SET_TYPE_IMM:
974 type = immediate;
975 typeName = bindTypeName(type);
976 break;
977 case BIND_OPCODE_SET_ADDEND_SLEB:
978 addend = read_sleb128(p, end);
979 break;
980 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
981 segIndex = immediate;
982 segStartAddr = segStartAddress(segIndex);
983 segName = segmentName(segIndex);
984 segOffset = read_uleb128(p, end);
985 break;
986 case BIND_OPCODE_ADD_ADDR_ULEB:
987 segOffset += read_uleb128(p, end);
988 break;
989 case BIND_OPCODE_DO_BIND:
990 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
991 segOffset += sizeof(pint_t);
992 break;
993 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
994 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
995 segOffset += read_uleb128(p, end) + sizeof(pint_t);
996 break;
997 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
998 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
999 segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
1000 break;
1001 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1002 count = read_uleb128(p, end);
1003 skip = read_uleb128(p, end);
1004 for (uint32_t i=0; i < count; ++i) {
1005 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
1006 segOffset += skip + sizeof(pint_t);
1008 break;
1009 default:
1010 throwf("bad bind opcode %d", *p);
1017 template <typename A>
1018 void DyldInfoPrinter<A>::printWeakBindingInfo()
1020 if ( (fInfo == NULL) || (fInfo->weak_bind_off() == 0) ) {
1021 printf("no weak binding\n");
1023 else {
1024 printf("weak binding information:\n");
1025 printf("segment section address type addend symbol\n");
1026 const uint8_t* p = (uint8_t*)fHeader + fInfo->weak_bind_off();
1027 const uint8_t* end = &p[fInfo->weak_bind_size()];
1029 uint8_t type = 0;
1030 uint8_t segIndex = 0;
1031 uint64_t segOffset = 0;
1032 const char* symbolName = NULL;
1033 int64_t addend = 0;
1034 uint32_t count;
1035 uint32_t skip;
1036 pint_t segStartAddr = 0;
1037 const char* segName = "??";
1038 const char* typeName = "??";
1039 bool done = false;
1040 while ( !done && (p < end) ) {
1041 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1042 uint8_t opcode = *p & BIND_OPCODE_MASK;
1043 ++p;
1044 switch (opcode) {
1045 case BIND_OPCODE_DONE:
1046 done = true;
1047 break;
1048 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1049 symbolName = (char*)p;
1050 while (*p != '\0')
1051 ++p;
1052 ++p;
1053 if ( (immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) != 0 )
1054 printf(" strong %s\n", symbolName );
1055 break;
1056 case BIND_OPCODE_SET_TYPE_IMM:
1057 type = immediate;
1058 typeName = bindTypeName(type);
1059 break;
1060 case BIND_OPCODE_SET_ADDEND_SLEB:
1061 addend = read_sleb128(p, end);
1062 break;
1063 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1064 segIndex = immediate;
1065 segStartAddr = segStartAddress(segIndex);
1066 segName = segmentName(segIndex);
1067 segOffset = read_uleb128(p, end);
1068 break;
1069 case BIND_OPCODE_ADD_ADDR_ULEB:
1070 segOffset += read_uleb128(p, end);
1071 break;
1072 case BIND_OPCODE_DO_BIND:
1073 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
1074 segOffset += sizeof(pint_t);
1075 break;
1076 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1077 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
1078 segOffset += read_uleb128(p, end) + sizeof(pint_t);
1079 break;
1080 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1081 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
1082 segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
1083 break;
1084 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1085 count = read_uleb128(p, end);
1086 skip = read_uleb128(p, end);
1087 for (uint32_t i=0; i < count; ++i) {
1088 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
1089 segOffset += skip + sizeof(pint_t);
1091 break;
1092 default:
1093 throwf("unknown weak bind opcode %d", *p);
1101 template <typename A>
1102 void DyldInfoPrinter<A>::printLazyBindingInfo()
1104 if ( fInfo == NULL ) {
1105 printf("no compressed dyld info\n");
1107 else if ( fInfo->lazy_bind_off() == 0 ) {
1108 printf("no compressed lazy binding info\n");
1110 else {
1111 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1112 printf("segment section address index dylib symbol\n");
1113 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
1114 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
1116 uint8_t type = BIND_TYPE_POINTER;
1117 uint8_t segIndex = 0;
1118 uint64_t segOffset = 0;
1119 const char* symbolName = NULL;
1120 const char* fromDylib = "??";
1121 int libraryOrdinal = 0;
1122 int64_t addend = 0;
1123 uint32_t lazy_offset = 0;
1124 pint_t segStartAddr = 0;
1125 const char* segName = "??";
1126 const char* typeName = "??";
1127 const char* weak_import = "";
1128 for (const uint8_t* p=start; p < end; ) {
1129 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1130 uint8_t opcode = *p & BIND_OPCODE_MASK;
1131 ++p;
1132 switch (opcode) {
1133 case BIND_OPCODE_DONE:
1134 lazy_offset = p-start;
1135 break;
1136 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1137 libraryOrdinal = immediate;
1138 fromDylib = ordinalName(libraryOrdinal);
1139 break;
1140 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1141 libraryOrdinal = read_uleb128(p, end);
1142 fromDylib = ordinalName(libraryOrdinal);
1143 break;
1144 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1145 // the special ordinals are negative numbers
1146 if ( immediate == 0 )
1147 libraryOrdinal = 0;
1148 else {
1149 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1150 libraryOrdinal = signExtended;
1152 fromDylib = ordinalName(libraryOrdinal);
1153 break;
1154 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1155 symbolName = (char*)p;
1156 while (*p != '\0')
1157 ++p;
1158 ++p;
1159 if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
1160 weak_import = " (weak import)";
1161 else
1162 weak_import = "";
1163 break;
1164 case BIND_OPCODE_SET_TYPE_IMM:
1165 type = immediate;
1166 typeName = bindTypeName(type);
1167 break;
1168 case BIND_OPCODE_SET_ADDEND_SLEB:
1169 addend = read_sleb128(p, end);
1170 break;
1171 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1172 segIndex = immediate;
1173 segStartAddr = segStartAddress(segIndex);
1174 segName = segmentName(segIndex);
1175 segOffset = read_uleb128(p, end);
1176 break;
1177 case BIND_OPCODE_ADD_ADDR_ULEB:
1178 segOffset += read_uleb128(p, end);
1179 break;
1180 case BIND_OPCODE_DO_BIND:
1181 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName, weak_import);
1182 segOffset += sizeof(pint_t);
1183 break;
1184 default:
1185 throwf("bad lazy bind opcode %d", *p);
1192 template <typename A>
1193 void DyldInfoPrinter<A>::printLazyBindingOpcodes()
1195 if ( fInfo == NULL ) {
1196 printf("no compressed dyld info\n");
1198 else if ( fInfo->lazy_bind_off() == 0 ) {
1199 printf("no compressed lazy binding info\n");
1201 else {
1202 printf("lazy binding opcodes:\n");
1203 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
1204 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
1205 uint8_t type = BIND_TYPE_POINTER;
1206 uint8_t flags;
1207 uint64_t address = fBaseAddress;
1208 const char* symbolName = NULL;
1209 int libraryOrdinal = 0;
1210 int64_t addend = 0;
1211 uint32_t segmentIndex = 0;
1212 uint32_t count;
1213 uint32_t skip;
1214 for (const uint8_t* p = start; p < end; ) {
1215 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1216 uint8_t opcode = *p & BIND_OPCODE_MASK;
1217 uint32_t opcodeOffset = p-start;
1218 ++p;
1219 switch (opcode) {
1220 case BIND_OPCODE_DONE:
1221 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
1222 break;
1223 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1224 libraryOrdinal = immediate;
1225 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1226 break;
1227 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1228 libraryOrdinal = read_uleb128(p, end);
1229 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
1230 break;
1231 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1232 // the special ordinals are negative numbers
1233 if ( immediate == 0 )
1234 libraryOrdinal = 0;
1235 else {
1236 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1237 libraryOrdinal = signExtended;
1239 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1240 break;
1241 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1242 flags = immediate;
1243 symbolName = (char*)p;
1244 while (*p != '\0')
1245 ++p;
1246 ++p;
1247 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
1248 break;
1249 case BIND_OPCODE_SET_TYPE_IMM:
1250 type = immediate;
1251 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
1252 break;
1253 case BIND_OPCODE_SET_ADDEND_SLEB:
1254 addend = read_sleb128(p, end);
1255 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
1256 break;
1257 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1258 segmentIndex = immediate;
1259 address = read_uleb128(p, end);
1260 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
1261 break;
1262 case BIND_OPCODE_ADD_ADDR_ULEB:
1263 skip = read_uleb128(p, end);
1264 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1265 break;
1266 case BIND_OPCODE_DO_BIND:
1267 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
1268 break;
1269 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1270 skip = read_uleb128(p, end);
1271 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1272 break;
1273 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1274 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
1275 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
1276 break;
1277 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1278 count = read_uleb128(p, end);
1279 skip = read_uleb128(p, end);
1280 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
1281 break;
1282 default:
1283 throwf("unknown bind opcode %d", *p);
1290 struct SortExportsByAddress
1292 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
1294 return ( left.address < right.address );
1298 template <typename A>
1299 void DyldInfoPrinter<A>::printExportInfo()
1301 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1302 printf("no compressed export info\n");
1304 else {
1305 printf("export information (from trie):\n");
1306 const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
1307 const uint8_t* end = &start[fInfo->export_size()];
1308 std::vector<mach_o::trie::Entry> list;
1309 parseTrie(start, end, list);
1310 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1311 for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) {
1312 const bool reExport = (it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT);
1313 const bool weakDef = (it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
1314 const bool threadLocal = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
1315 const bool abs = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
1316 const bool resolver = (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
1317 if ( reExport )
1318 printf("[re-export] ");
1319 else
1320 printf("0x%08llX ", fBaseAddress+it->address);
1321 printf("%s", it->name);
1322 if ( weakDef || threadLocal || resolver || abs ) {
1323 bool needComma = false;
1324 printf(" [");
1325 if ( weakDef ) {
1326 printf("weak_def");
1327 needComma = true;
1329 if ( threadLocal ) {
1330 if ( needComma )
1331 printf(", ");
1332 printf("per-thread");
1333 needComma = true;
1335 if ( abs ) {
1336 if ( needComma )
1337 printf(", ");
1338 printf("absolute");
1339 needComma = true;
1341 if ( resolver ) {
1342 if ( needComma )
1343 printf(", ");
1344 printf("resolver=0x%08llX", it->other);
1345 needComma = true;
1347 printf("]");
1349 if ( reExport ) {
1350 if ( it->importName[0] == '\0' )
1351 printf(" (from %s)", fDylibs[it->other - 1]);
1352 else
1353 printf(" (%s from %s)", it->importName, fDylibs[it->other - 1]);
1355 printf("\n");
1361 template <typename A>
1362 void DyldInfoPrinter<A>::processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
1363 const uint8_t* parent, const uint8_t* p,
1364 char* cummulativeString, int curStrOffset)
1366 const uint8_t* const me = p;
1367 const uint64_t terminalSize = read_uleb128(p, end);
1368 const uint8_t* children = p + terminalSize;
1369 if ( terminalSize != 0 ) {
1370 uint32_t flags = read_uleb128(p, end);
1371 if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
1372 uint64_t ordinal = read_uleb128(p, end);
1373 const char* importName = (const char*)p;
1374 while (*p != '\0')
1375 ++p;
1376 ++p;
1377 if ( *importName == '\0' )
1378 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me-start), cummulativeString, ordinal);
1379 else
1380 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me-start), cummulativeString, importName, ordinal);
1382 else {
1383 uint64_t address = read_uleb128(p, end);
1384 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address);
1385 if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
1386 read_uleb128(p, end);
1389 else {
1390 printf("\tnode%03ld;\n", (long)(me-start));
1392 const uint8_t childrenCount = *children++;
1393 const uint8_t* s = children;
1394 for (uint8_t i=0; i < childrenCount; ++i) {
1395 const char* edgeName = (char*)s;
1396 int edgeStrLen = 0;
1397 while (*s != '\0') {
1398 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1399 ++edgeStrLen;
1401 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1402 uint32_t childNodeOffet = read_uleb128(s, end);
1403 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me-start), childNodeOffet, edgeName);
1404 processExportGraphNode(start, end, start, start+childNodeOffet, cummulativeString, curStrOffset+edgeStrLen);
1408 template <typename A>
1409 void DyldInfoPrinter<A>::printExportInfoGraph()
1411 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1412 printf("no compressed export info\n");
1414 else {
1415 const uint8_t* p = (uint8_t*)fHeader + fInfo->export_off();
1416 const uint8_t* end = &p[fInfo->export_size()];
1417 char cummulativeString[2000];
1418 printf("digraph {\n");
1419 processExportGraphNode(p, end, p, p, cummulativeString, 0);
1420 printf("}\n");
1424 template <typename A>
1425 void DyldInfoPrinter<A>::gatherNodeStarts(const uint8_t* const start, const uint8_t* const end,
1426 const uint8_t* parent, const uint8_t* p,
1427 std::vector<uint32_t>& nodeStarts)
1429 nodeStarts.push_back(p-start);
1430 const uint8_t terminalSize = read_uleb128(p, end);
1431 const uint8_t* children = p + terminalSize;
1433 const uint8_t childrenCount = *children++;
1434 const uint8_t* s = children;
1435 for (uint8_t i=0; i < childrenCount; ++i) {
1436 // skip over edge string
1437 while (*s != '\0')
1438 ++s;
1439 ++s;
1440 uint32_t childNodeOffet = read_uleb128(s, end);
1441 gatherNodeStarts(start, end, start, start+childNodeOffet, nodeStarts);
1446 template <typename A>
1447 void DyldInfoPrinter<A>::printExportInfoNodes()
1449 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1450 printf("no compressed export info\n");
1452 else {
1453 const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
1454 const uint8_t* end = &start[fInfo->export_size()];
1455 std::vector<uint32_t> nodeStarts;
1456 gatherNodeStarts(start, end, start, start, nodeStarts);
1457 std::sort(nodeStarts.begin(), nodeStarts.end());
1458 for (std::vector<uint32_t>::const_iterator it=nodeStarts.begin(); it != nodeStarts.end(); ++it) {
1459 printf("0x%04X: ", *it);
1460 const uint8_t* p = start + *it;
1461 uint64_t exportInfoSize = read_uleb128(p, end);
1462 if ( exportInfoSize != 0 ) {
1463 // print terminal info
1464 uint64_t flags = read_uleb128(p, end);
1465 if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
1466 uint64_t ordinal = read_uleb128(p, end);
1467 const char* importName = (const char*)p;
1468 while (*p != '\0')
1469 ++p;
1470 ++p;
1471 if ( strlen(importName) == 0 )
1472 printf("[flags=REEXPORT ordinal=%llu] ", ordinal);
1473 else
1474 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal, importName);
1476 else if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
1477 uint64_t stub = read_uleb128(p, end);
1478 uint64_t resolver = read_uleb128(p, end);
1479 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub, resolver);
1481 else {
1482 uint64_t address = read_uleb128(p, end);
1483 if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR )
1484 printf("[addr=0x%06llX] ", address);
1485 else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)
1486 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address);
1487 else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE)
1488 printf("[flags=ABSOLUTE addr=0x%06llX] ", address);
1489 else
1490 printf("[flags=0x%llX addr=0x%06llX] ", flags, address);
1493 // print child edges
1494 const uint8_t childrenCount = *p++;
1495 for (uint8_t i=0; i < childrenCount; ++i) {
1496 const char* edgeName = (const char*)p;
1497 while (*p != '\0')
1498 ++p;
1499 ++p;
1500 uint32_t childNodeOffet = read_uleb128(p, end);
1501 printf("%s->0x%04X", edgeName, childNodeOffet);
1502 if ( i < (childrenCount-1) )
1503 printf(", ");
1505 printf("\n");
1512 template <typename A>
1513 const uint8_t* DyldInfoPrinter<A>::printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end, uint8_t kind)
1515 const char* kindStr = "??";
1516 switch (kind ) {
1517 case DYLD_CACHE_ADJ_V1_POINTER_32:
1518 kindStr = "32-bit pointer";
1519 break;
1520 case DYLD_CACHE_ADJ_V1_POINTER_64:
1521 kindStr = "64-bit pointer";
1522 break;
1523 case DYLD_CACHE_ADJ_V1_ADRP:
1524 kindStr = "arm64 ADRP";
1525 break;
1526 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+0:
1527 kindStr = "thumb2 movt low high 4 bits=0";
1528 break;
1529 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+1:
1530 kindStr = "thumb2 movt low high 4 bits=1";
1531 break;
1532 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+2:
1533 kindStr = "thumb2 movt low high 4 bits=2";
1534 break;
1535 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+3:
1536 kindStr = "thumb2 movt low high 4 bits=3";
1537 break;
1538 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+4:
1539 kindStr = "thumb2 movt low high 4 bits=4";
1540 break;
1541 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+5:
1542 kindStr = "thumb2 movt low high 4 bits=5";
1543 break;
1544 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+6:
1545 kindStr = "thumb2 movt low high 4 bits=6";
1546 break;
1547 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+7:
1548 kindStr = "thumb2 movt low high 4 bits=7";
1549 break;
1550 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+8:
1551 kindStr = "thumb2 movt low high 4 bits=8";
1552 break;
1553 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+9:
1554 kindStr = "thumb2 movt low high 4 bits=9";
1555 break;
1556 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+10:
1557 kindStr = "thumb2 movt low high 4 bits=10";
1558 break;
1559 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+11:
1560 kindStr = "thumb2 movt low high 4 bits=11";
1561 break;
1562 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+12:
1563 kindStr = "thumb2 movt low high 4 bits=12";
1564 break;
1565 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+13:
1566 kindStr = "thumb2 movt low high 4 bits=13";
1567 break;
1568 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+14:
1569 kindStr = "thumb2 movt low high 4 bits=14";
1570 break;
1571 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+15:
1572 kindStr = "thumb2 movt low high 4 bits=15";
1573 break;
1574 case DYLD_CACHE_ADJ_V1_ARM_MOVT+0:
1575 kindStr = "arm movt low high 4 bits=0";
1576 break;
1577 case DYLD_CACHE_ADJ_V1_ARM_MOVT+1:
1578 kindStr = "arm movt low high 4 bits=1";
1579 break;
1580 case DYLD_CACHE_ADJ_V1_ARM_MOVT+2:
1581 kindStr = "arm movt low high 4 bits=2";
1582 break;
1583 case DYLD_CACHE_ADJ_V1_ARM_MOVT+3:
1584 kindStr = "arm movt low high 4 bits=3";
1585 break;
1586 case DYLD_CACHE_ADJ_V1_ARM_MOVT+4:
1587 kindStr = "arm movt low high 4 bits=4";
1588 break;
1589 case DYLD_CACHE_ADJ_V1_ARM_MOVT+5:
1590 kindStr = "arm movt low high 4 bits=5";
1591 break;
1592 case DYLD_CACHE_ADJ_V1_ARM_MOVT+6:
1593 kindStr = "arm movt low high 4 bits=6";
1594 break;
1595 case DYLD_CACHE_ADJ_V1_ARM_MOVT+7:
1596 kindStr = "arm movt low high 4 bits=7";
1597 break;
1598 case DYLD_CACHE_ADJ_V1_ARM_MOVT+8:
1599 kindStr = "arm movt low high 4 bits=8";
1600 break;
1601 case DYLD_CACHE_ADJ_V1_ARM_MOVT+9:
1602 kindStr = "arm movt low high 4 bits=9";
1603 break;
1604 case DYLD_CACHE_ADJ_V1_ARM_MOVT+10:
1605 kindStr = "arm movt low high 4 bits=10";
1606 break;
1607 case DYLD_CACHE_ADJ_V1_ARM_MOVT+11:
1608 kindStr = "arm movt low high 4 bits=11";
1609 break;
1610 case DYLD_CACHE_ADJ_V1_ARM_MOVT+12:
1611 kindStr = "arm movt low high 4 bits=12";
1612 break;
1613 case DYLD_CACHE_ADJ_V1_ARM_MOVT+13:
1614 kindStr = "arm movt low high 4 bits=13";
1615 break;
1616 case DYLD_CACHE_ADJ_V1_ARM_MOVT+14:
1617 kindStr = "arm movt low high 4 bits=14";
1618 break;
1619 case DYLD_CACHE_ADJ_V1_ARM_MOVT+15:
1620 kindStr = "arm movt low high 4 bits=15";
1621 break;
1622 default:
1623 kindStr = "<<unknown>>";
1625 uint64_t address = 0;
1626 uint64_t delta = 0;
1627 do {
1628 delta = read_uleb128(p, end);
1629 address += delta;
1630 printf("0x%0llX %s\n", address+fBaseAddress, kindStr);
1631 } while (delta);
1633 return p;
1636 template <typename A>
1637 void DyldInfoPrinter<A>::printSharedRegionInfo()
1639 if ( (fSharedRegionInfo == NULL) || (fSharedRegionInfo->datasize() == 0) ) {
1640 printf("no shared region info\n");
1642 else {
1643 const uint8_t* infoStart = (uint8_t*)fHeader + fSharedRegionInfo->dataoff();
1644 const uint8_t* infoEnd = &infoStart[fSharedRegionInfo->datasize()];
1645 if ( *infoStart == DYLD_CACHE_ADJ_V2_FORMAT ) {
1646 ++infoStart;
1647 // Whole :== <count> FromToSection+
1648 // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
1649 // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
1650 // FromOffset :== <kind> <count> <from-sect-offset-delta>
1651 const uint8_t* p = infoStart;
1652 uint64_t sectionCount = read_uleb128(p, infoEnd);
1653 for (uint64_t i=0; i < sectionCount; ++i) {
1654 uint64_t fromSectionIndex = read_uleb128(p, infoEnd);
1655 uint64_t toSectionIndex = read_uleb128(p, infoEnd);
1656 uint64_t toOffsetCount = read_uleb128(p, infoEnd);
1657 const macho_section<P>* fromSection = fSections[fromSectionIndex];
1658 const macho_section<P>* toSection = fSections[toSectionIndex];
1659 char fromSectionName[20];
1660 strncpy(fromSectionName, fromSection->sectname(), 16);
1661 fromSectionName[16] = '\0';
1662 printf("from sect=%s/%s, to sect=%s/%s, count=%lld:\n", fromSection->segname(), fromSectionName, toSection->segname(), toSection->sectname(), toOffsetCount);
1663 uint64_t toSectionOffset = 0;
1664 const char* lastFromSymbol = NULL;
1665 for (uint64_t j=0; j < toOffsetCount; ++j) {
1666 uint64_t toSectionDelta = read_uleb128(p, infoEnd);
1667 uint64_t fromOffsetCount = read_uleb128(p, infoEnd);
1668 toSectionOffset += toSectionDelta;
1669 for (uint64_t k=0; k < fromOffsetCount; ++k) {
1670 uint64_t kind = read_uleb128(p, infoEnd);
1671 uint64_t fromSectDeltaCount = read_uleb128(p, infoEnd);
1672 uint64_t fromSectionOffset = 0;
1673 for (uint64_t l=0; l < fromSectDeltaCount; ++l) {
1674 uint64_t delta = read_uleb128(p, infoEnd);
1675 fromSectionOffset += delta;
1676 uint64_t symbolOffset;
1677 const char* s = closestSymbolNameForAddress(fromSection->addr()+fromSectionOffset, &symbolOffset, fromSectionIndex);
1678 if ( (s != lastFromSymbol) && (s != NULL) )
1679 printf(" %s:\n", s);
1680 const char* toSymbol = closestSymbolNameForAddress(toSection->addr()+toSectionOffset, &symbolOffset, toSectionIndex);
1681 printf(" from addr=0x%0llX %s to addr=0x%0llX", fromSection->addr()+fromSectionOffset, sharedRegionKindName(kind), toSection->addr()+toSectionOffset);
1682 if ( toSymbol != NULL ) {
1683 if ( symbolOffset == 0 )
1684 printf(" (%s)", toSymbol);
1685 else
1686 printf(" (%s + %lld)", toSymbol, symbolOffset);
1688 printf("\n");
1689 lastFromSymbol = s;
1695 else {
1696 for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
1697 uint8_t kind = *p++;
1698 p = this->printSharedRegionV1InfoForEachULEB128Address(p, infoEnd, kind);
1704 template <typename A>
1705 const char* DyldInfoPrinter<A>::sharedRegionKindName(uint8_t kind)
1707 switch (kind) {
1708 default:
1709 return "<<unknown>>";
1710 case DYLD_CACHE_ADJ_V2_POINTER_32:
1711 return "pointer32";
1712 case DYLD_CACHE_ADJ_V2_POINTER_64:
1713 return "pointer64";
1714 case DYLD_CACHE_ADJ_V2_DELTA_32:
1715 return "delta32";
1716 case DYLD_CACHE_ADJ_V2_DELTA_64:
1717 return "delta64";
1718 case DYLD_CACHE_ADJ_V2_ARM64_ADRP:
1719 return "adrp";
1720 case DYLD_CACHE_ADJ_V2_ARM64_OFF12:
1721 return "off12";
1722 case DYLD_CACHE_ADJ_V2_ARM64_BR26:
1723 return "br26";
1724 case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT:
1725 return "movw/movt";
1726 case DYLD_CACHE_ADJ_V2_ARM_BR24:
1727 return "br24";
1728 case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT:
1729 return "movw/movt";
1730 case DYLD_CACHE_ADJ_V2_THUMB_BR22:
1731 return "br22";
1732 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
1733 return "off32";
1738 #if SUPPORT_ARCH_arm_any
1739 template <>
1740 void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
1742 if ( addr & 1 )
1743 printf("0x%0llX [thumb] %s\n", (addr & -2), symbolNameForAddress(addr & -2));
1744 else
1745 printf("0x%0llX %s\n", addr, symbolNameForAddress(addr));
1747 #endif
1749 template <typename A>
1750 void DyldInfoPrinter<A>::printFunctionStartLine(uint64_t addr)
1752 printf("0x%0llX %s\n", addr, symbolNameForAddress(addr));
1756 template <typename A>
1757 void DyldInfoPrinter<A>::printFunctionStartsInfo()
1759 if ( (fFunctionStartsInfo == NULL) || (fFunctionStartsInfo->datasize() == 0) ) {
1760 printf("no function starts info\n");
1762 else {
1763 const uint8_t* infoStart = (uint8_t*)fHeader + fFunctionStartsInfo->dataoff();
1764 const uint8_t* infoEnd = &infoStart[fFunctionStartsInfo->datasize()];
1765 uint64_t address = fBaseAddress;
1766 for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd); ) {
1767 uint64_t delta = 0;
1768 uint32_t shift = 0;
1769 bool more = true;
1770 do {
1771 uint8_t byte = *p++;
1772 delta |= ((byte & 0x7F) << shift);
1773 shift += 7;
1774 if ( byte < 0x80 ) {
1775 address += delta;
1776 printFunctionStartLine(address);
1777 more = false;
1779 } while (more);
1784 template <typename A>
1785 void DyldInfoPrinter<A>::printDylibsInfo()
1787 printf("attributes dependent dylibs\n");
1788 for(typename std::vector<const macho_dylib_command<P>*>::iterator it = fDylibLoadCommands.begin(); it != fDylibLoadCommands.end(); ++it) {
1789 const macho_dylib_command<P>* dylib = *it;
1790 const char* attribute = "";
1791 switch ( dylib->cmd() ) {
1792 case LC_LOAD_WEAK_DYLIB:
1793 attribute = "weak_import";
1794 break;
1795 case LC_REEXPORT_DYLIB:
1796 attribute = "re-export";
1797 break;
1798 case LC_LOAD_UPWARD_DYLIB:
1799 attribute = "upward";
1800 break;
1801 case LC_LAZY_LOAD_DYLIB:
1802 attribute = "lazy_load";
1803 break;
1804 case LC_LOAD_DYLIB:
1805 default:
1806 break;
1808 printf(" %-12s %s\n", attribute, dylib->name());
1812 template <typename A>
1813 void DyldInfoPrinter<A>::printDRInfo()
1815 if ( fDRInfo == NULL ) {
1816 printf("no Designated Requirements info\n");
1818 else {
1819 printf("dylibs DRs\n");
1820 const uint8_t* start = ((uint8_t*)fHeader + fDRInfo->dataoff());
1821 //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
1822 typedef Security::SuperBlob<Security::kSecCodeMagicDRList> DRListSuperBlob;
1823 const DRListSuperBlob* topBlob = (DRListSuperBlob*)start;
1824 if ( topBlob->validateBlob(fDRInfo->datasize()) ) {
1825 if ( topBlob->count() == fDylibLoadCommands.size() ) {
1826 for(unsigned i=0; i < topBlob->count(); ++i) {
1827 printf(" %-20s ", fDylibs[i]);
1828 const Security::BlobCore* item = topBlob->find(i);
1829 if ( item != NULL ) {
1830 const uint8_t* itemStart = (uint8_t*)item;
1831 const uint8_t* itemEnd = itemStart + item->length();
1832 for(const uint8_t* p=itemStart; p < itemEnd; ++p)
1833 printf("%02X ", *p);
1835 else {
1836 printf("no DR info");
1838 printf("\n");
1841 else {
1842 fprintf(stderr, "superblob of DRs has a different number of elements than dylib load commands\n");
1845 else {
1846 fprintf(stderr, "superblob of DRs invalid\n");
1855 template <typename A>
1856 void DyldInfoPrinter<A>::printDataInCode()
1858 if ( fDataInCode == NULL ) {
1859 printf("no data-in-code info\n");
1861 else {
1862 printf("offset length data-kind\n");
1863 const macho_data_in_code_entry<P>* start = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff());
1864 const macho_data_in_code_entry<P>* end = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff() + fDataInCode->datasize());
1865 for (const macho_data_in_code_entry<P>* p=start; p < end; ++p) {
1866 const char* kindStr = "???";
1867 switch ( p->kind() ) {
1868 case 1:
1869 kindStr = "data";
1870 break;
1871 case 2:
1872 kindStr = "jumptable8";
1873 break;
1874 case 3:
1875 kindStr = "jumptable16";
1876 break;
1877 case 4:
1878 kindStr = "jumptable32";
1879 break;
1880 case 5:
1881 kindStr = "jumptable32absolute";
1882 break;
1884 printf("0x%08X 0x%04X %s\n", p->offset(), p->length(), kindStr);
1891 template <>
1892 ppc::P::uint_t DyldInfoPrinter<ppc>::relocBase()
1894 if ( fHeader->flags() & MH_SPLIT_SEGS )
1895 return fFirstWritableSegment->vmaddr();
1896 else
1897 return fFirstSegment->vmaddr();
1900 template <>
1901 ppc64::P::uint_t DyldInfoPrinter<ppc64>::relocBase()
1903 if ( fWriteableSegmentWithAddrOver4G )
1904 return fFirstWritableSegment->vmaddr();
1905 else
1906 return fFirstSegment->vmaddr();
1909 template <>
1910 x86::P::uint_t DyldInfoPrinter<x86>::relocBase()
1912 if ( fHeader->flags() & MH_SPLIT_SEGS )
1913 return fFirstWritableSegment->vmaddr();
1914 else
1915 return fFirstSegment->vmaddr();
1918 template <>
1919 x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
1921 return fFirstWritableSegment->vmaddr();
1924 #if SUPPORT_ARCH_arm_any
1925 template <>
1926 arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
1928 if ( fHeader->flags() & MH_SPLIT_SEGS )
1929 return fFirstWritableSegment->vmaddr();
1930 else
1931 return fFirstSegment->vmaddr();
1933 #endif
1935 #if SUPPORT_ARCH_arm64
1936 template <>
1937 arm64::P::uint_t DyldInfoPrinter<arm64>::relocBase()
1939 return fFirstWritableSegment->vmaddr();
1941 #endif
1944 template <>
1945 const char* DyldInfoPrinter<ppc>::relocTypeName(uint8_t r_type)
1947 if ( r_type == GENERIC_RELOC_VANILLA )
1948 return "pointer";
1949 else
1950 return "??";
1953 template <>
1954 const char* DyldInfoPrinter<ppc64>::relocTypeName(uint8_t r_type)
1956 if ( r_type == GENERIC_RELOC_VANILLA )
1957 return "pointer";
1958 else
1959 return "??";
1962 template <>
1963 const char* DyldInfoPrinter<x86>::relocTypeName(uint8_t r_type)
1965 if ( r_type == GENERIC_RELOC_VANILLA )
1966 return "pointer";
1967 else if ( r_type == GENERIC_RELOC_PB_LA_PTR )
1968 return "pb pointer";
1969 else
1970 return "??";
1973 template <>
1974 const char* DyldInfoPrinter<x86_64>::relocTypeName(uint8_t r_type)
1976 if ( r_type == X86_64_RELOC_UNSIGNED )
1977 return "pointer";
1978 else
1979 return "??";
1982 #if SUPPORT_ARCH_arm_any
1983 template <>
1984 const char* DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
1986 if ( r_type == ARM_RELOC_VANILLA )
1987 return "pointer";
1988 else if ( r_type == ARM_RELOC_PB_LA_PTR )
1989 return "pb pointer";
1990 else
1991 return "??";
1993 #endif
1995 #if SUPPORT_ARCH_arm64
1996 template <>
1997 const char* DyldInfoPrinter<arm64>::relocTypeName(uint8_t r_type)
1999 if ( r_type == ARM64_RELOC_UNSIGNED )
2000 return "pointer";
2001 return "??";
2003 #endif
2006 template <typename A>
2007 void DyldInfoPrinter<A>::printRelocRebaseInfo()
2009 if ( fDynamicSymbolTable == NULL ) {
2010 printf("no classic dynamic symbol table");
2012 else {
2013 printf("rebase information (from local relocation records and indirect symbol table):\n");
2014 printf("segment section address type\n");
2015 // walk all local relocations
2016 pint_t rbase = relocBase();
2017 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + fDynamicSymbolTable->locreloff());
2018 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nlocrel()];
2019 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
2020 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
2021 pint_t addr = reloc->r_address() + rbase;
2022 uint8_t segIndex = segmentIndexForAddress(addr);
2023 const char* typeName = relocTypeName(reloc->r_type());
2024 const char* segName = segmentName(segIndex);
2025 const char* sectName = sectionName(segIndex, addr);
2026 printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
2028 else {
2029 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
2030 pint_t addr = sreloc->r_address() + rbase;
2031 uint8_t segIndex = segmentIndexForAddress(addr);
2032 const char* typeName = relocTypeName(sreloc->r_type());
2033 const char* segName = segmentName(segIndex);
2034 const char* sectName = sectionName(segIndex, addr);
2035 printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
2038 // look for local non-lazy-pointers
2039 const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
2040 uint8_t segIndex = 0;
2041 for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit, ++segIndex) {
2042 const macho_segment_command<P>* segCmd = *segit;
2043 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
2044 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
2045 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
2046 uint8_t type = sect->flags() & SECTION_TYPE;
2047 if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
2048 uint32_t indirectOffset = sect->reserved1();
2049 uint32_t count = sect->size() / sizeof(pint_t);
2050 for (uint32_t i=0; i < count; ++i) {
2051 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
2052 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
2053 pint_t addr = sect->addr() + i*sizeof(pint_t);
2054 const char* typeName = "pointer";
2055 const char* segName = segmentName(segIndex);
2056 const char* sectName = sectionName(segIndex, addr);
2057 printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
2067 template <typename A>
2068 void DyldInfoPrinter<A>::printSymbolTableExportInfo()
2070 if ( fDynamicSymbolTable == NULL ) {
2071 printf("no classic dynamic symbol table");
2073 else {
2074 printf("export information (from symbol table):\n");
2075 const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
2076 for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
2077 const char* flags = "";
2078 if ( sym->n_desc() & N_WEAK_DEF )
2079 flags = "[weak_def] ";
2080 pint_t thumb = 0;
2081 if ( sym->n_desc() & N_ARM_THUMB_DEF )
2082 thumb = 1;
2083 printf("0x%08llX %s%s\n", sym->n_value()+thumb, flags, &fStrings[sym->n_strx()]);
2088 template <typename A>
2089 const char* DyldInfoPrinter<A>::closestSymbolNameForAddress(uint64_t addr, uint64_t* offset, uint8_t sectIndex)
2091 const macho_nlist<P>* bestSymbol = NULL;
2092 if ( fDynamicSymbolTable != NULL ) {
2093 // find closest match in globals
2094 const macho_nlist<P>* const globalsStart = &fSymbols[fDynamicSymbolTable->iextdefsym()];
2095 const macho_nlist<P>* const globalsEnd = &globalsStart[fDynamicSymbolTable->nextdefsym()];
2096 for (const macho_nlist<P>* s = globalsStart; s < globalsEnd; ++s) {
2097 if ( (s->n_type() & N_TYPE) == N_SECT ) {
2098 if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
2099 if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
2100 bestSymbol = s;
2105 // find closest match in locals
2106 const macho_nlist<P>* const localsStart = &fSymbols[fDynamicSymbolTable->ilocalsym()];
2107 const macho_nlist<P>* const localsEnd = &localsStart[fDynamicSymbolTable->nlocalsym()];
2108 for (const macho_nlist<P>* s = localsStart; s < localsEnd; ++s) {
2109 if ( ((s->n_type() & N_TYPE) == N_SECT) && ((s->n_type() & N_STAB) == 0) ) {
2110 if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
2111 if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
2112 bestSymbol = s;
2117 else {
2118 // find closest match in locals
2119 const macho_nlist<P>* const allStart = &fSymbols[0];
2120 const macho_nlist<P>* const allEnd = &fSymbols[fSymbolCount];
2121 for (const macho_nlist<P>* s = allStart; s < allEnd; ++s) {
2122 if ( ((s->n_type() & N_TYPE) == N_SECT) && ((s->n_type() & N_STAB) == 0) ) {
2123 if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
2124 if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
2125 bestSymbol = s;
2130 if ( bestSymbol != NULL ) {
2131 *offset = addr - bestSymbol->n_value();
2132 return &fStrings[bestSymbol->n_strx()];
2134 *offset = 0;
2135 return NULL;
2138 template <typename A>
2139 const char* DyldInfoPrinter<A>::symbolNameForAddress(uint64_t addr)
2141 uint64_t offset;
2142 const char* s = closestSymbolNameForAddress(addr, &offset);
2143 if ( (offset == 0) && (s != NULL) )
2144 return s;
2145 return "?";
2148 template <typename A>
2149 void DyldInfoPrinter<A>::printClassicBindingInfo()
2151 if ( fDynamicSymbolTable == NULL ) {
2152 printf("no classic dynamic symbol table");
2154 else {
2155 printf("binding information (from relocations and indirect symbol table):\n");
2156 printf("segment section address type weak addend dylib symbol\n");
2157 // walk all external relocations
2158 pint_t rbase = relocBase();
2159 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + fDynamicSymbolTable->extreloff());
2160 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nextrel()];
2161 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
2162 pint_t addr = reloc->r_address() + rbase;
2163 uint32_t symbolIndex = reloc->r_symbolnum();
2164 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2165 const char* symbolName = &fStrings[sym->n_strx()];
2166 const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : "";
2167 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
2168 uint8_t segIndex = segmentIndexForAddress(addr);
2169 const char* typeName = relocTypeName(reloc->r_type());
2170 const char* segName = segmentName(segIndex);
2171 const char* sectName = sectionName(segIndex, addr);
2172 const pint_t* addressMapped = mappedAddressForVMAddress(addr);
2173 int64_t addend = P::getP(*addressMapped);
2174 if ( fHeader->flags() & MH_PREBOUND ) {
2175 // In prebound binaries the content is already pointing to the target.
2176 // To get the addend requires subtracting out the base address it was prebound to.
2177 addend -= sym->n_value();
2179 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr,
2180 typeName, weak_import, addend, fromDylib, symbolName);
2182 // look for non-lazy pointers
2183 const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
2184 for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) {
2185 const macho_segment_command<P>* segCmd = *segit;
2186 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
2187 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
2188 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
2189 uint8_t type = sect->flags() & SECTION_TYPE;
2190 if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
2191 uint32_t indirectOffset = sect->reserved1();
2192 uint32_t count = sect->size() / sizeof(pint_t);
2193 for (uint32_t i=0; i < count; ++i) {
2194 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
2195 if ( symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
2196 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2197 const char* symbolName = &fStrings[sym->n_strx()];
2198 const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : "";
2199 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
2200 pint_t addr = sect->addr() + i*sizeof(pint_t);
2201 uint8_t segIndex = segmentIndexForAddress(addr);
2202 const char* typeName = "pointer";
2203 const char* segName = segmentName(segIndex);
2204 const char* sectName = sectionName(segIndex, addr);
2205 int64_t addend = 0;
2206 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr,
2207 typeName, weak_import, addend, fromDylib, symbolName);
2217 template <typename A>
2218 void DyldInfoPrinter<A>::printClassicLazyBindingInfo()
2220 if ( fDynamicSymbolTable == NULL ) {
2221 printf("no classic dynamic symbol table");
2223 else {
2224 printf("lazy binding information (from section records and indirect symbol table):\n");
2225 printf("segment section address index dylib symbol\n");
2226 const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
2227 for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) {
2228 const macho_segment_command<P>* segCmd = *segit;
2229 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
2230 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
2231 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
2232 uint8_t type = sect->flags() & SECTION_TYPE;
2233 if ( type == S_LAZY_SYMBOL_POINTERS ) {
2234 uint32_t indirectOffset = sect->reserved1();
2235 uint32_t count = sect->size() / sizeof(pint_t);
2236 for (uint32_t i=0; i < count; ++i) {
2237 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
2238 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2239 const char* symbolName = &fStrings[sym->n_strx()];
2240 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
2241 pint_t addr = sect->addr() + i*sizeof(pint_t);
2242 uint8_t segIndex = segmentIndexForAddress(addr);
2243 const char* segName = segmentName(segIndex);
2244 const char* sectName = sectionName(segIndex, addr);
2245 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName);
2248 else if ( (type == S_SYMBOL_STUBS) && (((sect->flags() & S_ATTR_SELF_MODIFYING_CODE) != 0)) && (sect->reserved2() == 5) ) {
2249 // i386 self-modifying stubs
2250 uint32_t indirectOffset = sect->reserved1();
2251 uint32_t count = sect->size() / 5;
2252 for (uint32_t i=0; i < count; ++i) {
2253 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
2254 if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
2255 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2256 const char* symbolName = &fStrings[sym->n_strx()];
2257 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
2258 pint_t addr = sect->addr() + i*5;
2259 uint8_t segIndex = segmentIndexForAddress(addr);
2260 const char* segName = segmentName(segIndex);
2261 const char* sectName = sectionName(segIndex, addr);
2262 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName);
2271 static void dump(const char* path)
2273 struct stat stat_buf;
2275 try {
2276 int fd = ::open(path, O_RDONLY, 0);
2277 if ( fd == -1 )
2278 throw "cannot open file";
2279 if ( ::fstat(fd, &stat_buf) != 0 )
2280 throwf("fstat(%s) failed, errno=%d\n", path, errno);
2281 uint32_t length = stat_buf.st_size;
2282 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
2283 if ( p == ((uint8_t*)(-1)) )
2284 throw "cannot map file";
2285 ::close(fd);
2286 const mach_header* mh = (mach_header*)p;
2287 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
2288 const struct fat_header* fh = (struct fat_header*)p;
2289 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
2290 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
2291 size_t offset = OSSwapBigToHostInt32(archs[i].offset);
2292 size_t size = OSSwapBigToHostInt32(archs[i].size);
2293 cpu_type_t cputype = OSSwapBigToHostInt32(archs[i].cputype);
2294 cpu_type_t cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);
2295 if ( ((cputype == sPreferredArch)
2296 && ((sPreferredSubArch==0) || (sPreferredSubArch==cpusubtype)))
2297 || (sPreferredArch == 0) ) {
2298 switch(cputype) {
2299 case CPU_TYPE_POWERPC:
2300 if ( DyldInfoPrinter<ppc>::validFile(p + offset) )
2301 DyldInfoPrinter<ppc>::make(p + offset, size, path, (sPreferredArch == 0));
2302 else
2303 throw "in universal file, ppc slice does not contain ppc mach-o";
2304 break;
2305 case CPU_TYPE_I386:
2306 if ( DyldInfoPrinter<x86>::validFile(p + offset) )
2307 DyldInfoPrinter<x86>::make(p + offset, size, path, (sPreferredArch == 0));
2308 else
2309 throw "in universal file, i386 slice does not contain i386 mach-o";
2310 break;
2311 case CPU_TYPE_POWERPC64:
2312 if ( DyldInfoPrinter<ppc64>::validFile(p + offset) )
2313 DyldInfoPrinter<ppc64>::make(p + offset, size, path, (sPreferredArch == 0));
2314 else
2315 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
2316 break;
2317 case CPU_TYPE_X86_64:
2318 if ( DyldInfoPrinter<x86_64>::validFile(p + offset) )
2319 DyldInfoPrinter<x86_64>::make(p + offset, size, path, (sPreferredArch == 0));
2320 else
2321 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
2322 break;
2323 #if SUPPORT_ARCH_arm_any
2324 case CPU_TYPE_ARM:
2325 if ( DyldInfoPrinter<arm>::validFile(p + offset) )
2326 DyldInfoPrinter<arm>::make(p + offset, size, path, (sPreferredArch == 0));
2327 else
2328 throw "in universal file, arm slice does not contain arm mach-o";
2329 break;
2330 #endif
2331 #if SUPPORT_ARCH_arm64
2332 case CPU_TYPE_ARM64:
2333 if ( DyldInfoPrinter<arm64>::validFile(p + offset) )
2334 DyldInfoPrinter<arm64>::make(p + offset, size, path, (sPreferredArch == 0));
2335 else
2336 throw "in universal file, arm64 slice does not contain arm64 mach-o";
2337 break;
2338 #endif
2339 default:
2340 throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
2345 else if ( DyldInfoPrinter<x86>::validFile(p) ) {
2346 DyldInfoPrinter<x86>::make(p, length, path, false);
2348 else if ( DyldInfoPrinter<ppc>::validFile(p) ) {
2349 DyldInfoPrinter<ppc>::make(p, length, path, false);
2351 else if ( DyldInfoPrinter<ppc64>::validFile(p) ) {
2352 DyldInfoPrinter<ppc64>::make(p, length, path, false);
2354 else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
2355 DyldInfoPrinter<x86_64>::make(p, length, path, false);
2357 #if SUPPORT_ARCH_arm_any
2358 else if ( DyldInfoPrinter<arm>::validFile(p) ) {
2359 DyldInfoPrinter<arm>::make(p, length, path, false);
2361 #endif
2362 #if SUPPORT_ARCH_arm64
2363 else if ( DyldInfoPrinter<arm64>::validFile(p) ) {
2364 DyldInfoPrinter<arm64>::make(p, length, path, false);
2366 #endif
2367 else {
2368 throw "not a known file type";
2371 catch (const char* msg) {
2372 throwf("%s in %s", msg, path);
2376 static void usage()
2378 fprintf(stdout, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
2379 "\t-dylibs print dependent dylibs\n"
2380 "\t-dr print dependent dylibs and show any recorded DR info\n"
2381 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
2382 "\t-bind print addresses dyld will set based on symbolic lookups\n"
2383 "\t-weak_bind print symbols which dyld must coalesce\n"
2384 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
2385 "\t-export print addresses of all symbols this file exports\n"
2386 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
2387 "\t-function_starts print table of function start addresses\n"
2388 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
2389 "\t-data_in_code print any data-in-code information\n"
2394 int main(int argc, const char* argv[])
2396 if ( argc == 1 ) {
2397 usage();
2398 return 0;
2401 try {
2402 std::vector<const char*> files;
2403 for(int i=1; i < argc; ++i) {
2404 const char* arg = argv[i];
2405 if ( arg[0] == '-' ) {
2406 if(strcmp(arg, "--version") == 0){
2407 /* Implement a gnu-style --version. */
2408 fprintf(stdout, "xtools-%s dyldinfo %s\nBased on Apple Inc. ld64-%s\n",
2409 XTOOLS_VERSION, PACKAGE_VERSION, LD64_VERSION_NUM);
2410 exit(0);
2411 } else if(strcmp(arg, "--help") == 0){
2412 usage();
2413 #ifdef XTOOLS_BUGURL
2414 fprintf(stdout, "Please report bugs to %s\n", XTOOLS_BUGURL);
2415 #endif
2416 exit(0);
2418 if ( strcmp(arg, "-arch") == 0 ) {
2419 const char* arch = ++i<argc? argv[i]: "";
2420 if ( strcmp(arch, "ppc64") == 0 )
2421 sPreferredArch = CPU_TYPE_POWERPC64;
2422 else if ( strcmp(arch, "ppc") == 0 )
2423 sPreferredArch = CPU_TYPE_POWERPC;
2424 else if ( strcmp(arch, "i386") == 0 )
2425 sPreferredArch = CPU_TYPE_I386;
2426 else if ( strcmp(arch, "x86_64") == 0 )
2427 sPreferredArch = CPU_TYPE_X86_64;
2428 #if SUPPORT_ARCH_arm64
2429 else if ( strcmp(arch, "arm64") == 0 )
2430 sPreferredArch = CPU_TYPE_ARM64;
2431 #endif
2432 else {
2433 if ( arch == NULL )
2434 throw "-arch missing architecture name";
2435 bool found = false;
2436 for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
2437 if ( strcmp(t->archName,arch) == 0 ) {
2438 sPreferredArch = t->cpuType;
2439 if ( t->isSubType )
2440 sPreferredSubArch = t->cpuSubType;
2441 found = true;
2442 break;
2445 if ( !found )
2446 throwf("unknown architecture %s", arch);
2449 else if ( strcmp(arg, "-rebase") == 0 ) {
2450 printRebase = true;
2452 else if ( strcmp(arg, "-bind") == 0 ) {
2453 printBind = true;
2455 else if ( strcmp(arg, "-weak_bind") == 0 ) {
2456 printWeakBind = true;
2458 else if ( strcmp(arg, "-lazy_bind") == 0 ) {
2459 printLazyBind = true;
2461 else if ( strcmp(arg, "-export") == 0 ) {
2462 printExport = true;
2464 else if ( strcmp(arg, "-opcodes") == 0 ) {
2465 printOpcodes = true;
2467 else if ( strcmp(arg, "-export_dot") == 0 ) {
2468 printExportGraph = true;
2470 else if ( strcmp(arg, "-export_trie_nodes") == 0 ) {
2471 printExportNodes = true;
2473 else if ( strcmp(arg, "-shared_region") == 0 ) {
2474 printSharedRegion = true;
2476 else if ( strcmp(arg, "-function_starts") == 0 ) {
2477 printFunctionStarts = true;
2479 else if ( strcmp(arg, "-dylibs") == 0 ) {
2480 printDylibs = true;
2482 else if ( strcmp(arg, "-dr") == 0 ) {
2483 printDRs = true;
2485 else if ( strcmp(arg, "-data_in_code") == 0 ) {
2486 printDataCode = true;
2488 else {
2489 throwf("unknown option: %s\n", arg);
2492 else {
2493 files.push_back(arg);
2496 if ( files.size() == 0 )
2497 usage();
2498 if ( files.size() == 1 ) {
2499 dump(files[0]);
2501 else {
2502 for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
2503 printf("\n%s:\n", *it);
2504 dump(*it);
2508 catch (const char* msg) {
2509 fprintf(stderr, "dyldinfo failed: %s\n", msg);
2510 return 1;
2513 return 0;