]> git.saurik.com Git - apple/ld64.git/blob - src/other/dyldinfo.cpp
ld64-264.3.102.tar.gz
[apple/ld64.git] / src / other / dyldinfo.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
4 *
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.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
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>
33
34 #include <vector>
35 #include <set>
36 #include <unordered_set>
37
38 #include "configure.h"
39 #include "MachOFileAbstraction.hpp"
40 #include "Architectures.hpp"
41 #include "MachOTrie.hpp"
42 #include "../ld/code-sign-blobs/superblob.h"
43
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;
59
60
61 __attribute__((noreturn))
62 static void throwf(const char* format, ...)
63 {
64 va_list list;
65 char* p;
66 va_start(list, format);
67 vasprintf(&p, format, list);
68 va_end(list);
69
70 const char* t = p;
71 throw t;
72 }
73
74
75 template <typename A>
76 class DyldInfoPrinter
77 {
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() {}
83
84
85 private:
86 typedef typename A::P P;
87 typedef typename A::P::E E;
88 typedef typename A::P::uint_t pint_t;
89
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);
119
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);
140
141
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;
164 };
165
166
167
168 template <>
169 bool DyldInfoPrinter<ppc>::validFile(const uint8_t* fileContent)
170 {
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;
183 }
184 return false;
185 }
186
187 template <>
188 bool DyldInfoPrinter<ppc64>::validFile(const uint8_t* fileContent)
189 {
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;
202 }
203 return false;
204 }
205
206 template <>
207 bool DyldInfoPrinter<x86>::validFile(const uint8_t* fileContent)
208 {
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;
221 }
222 return false;
223 }
224
225 template <>
226 bool DyldInfoPrinter<x86_64>::validFile(const uint8_t* fileContent)
227 {
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 return true;
240 }
241 return false;
242 }
243
244 #if SUPPORT_ARCH_arm_any
245 template <>
246 bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
247 {
248 const macho_header<P>* header = (const macho_header<P>*)fileContent;
249 if ( header->magic() != MH_MAGIC )
250 return false;
251 if ( header->cputype() != CPU_TYPE_ARM )
252 return false;
253 switch (header->filetype()) {
254 case MH_EXECUTE:
255 case MH_DYLIB:
256 case MH_DYLIB_STUB:
257 case MH_BUNDLE:
258 case MH_DYLINKER:
259 return true;
260 }
261 return false;
262 }
263 #endif
264
265 #if SUPPORT_ARCH_arm64
266 template <>
267 bool DyldInfoPrinter<arm64>::validFile(const uint8_t* fileContent)
268 {
269 const macho_header<P>* header = (const macho_header<P>*)fileContent;
270 if ( header->magic() != MH_MAGIC_64 )
271 return false;
272 if ( header->cputype() != CPU_TYPE_ARM64 )
273 return false;
274 switch (header->filetype()) {
275 case MH_EXECUTE:
276 case MH_DYLIB:
277 case MH_BUNDLE:
278 case MH_DYLINKER:
279 return true;
280 }
281 return false;
282 }
283 #endif
284
285 template <typename A>
286 DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
287 : fHeader(NULL), fLength(fileLength),
288 fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL),
289 fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), fDataInCode(NULL), fDRInfo(NULL),
290 fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL),
291 fWriteableSegmentWithAddrOver4G(false)
292 {
293 // sanity check
294 if ( ! validFile(fileContent) )
295 throw "not a mach-o file that can be checked";
296
297 fPath = strdup(path);
298 fHeader = (const macho_header<P>*)fileContent;
299
300 fMachHeaderPseudoSection.set_segname("__TEXT");
301 fMachHeaderPseudoSection.set_sectname("");
302 fMachHeaderPseudoSection.set_addr(0);
303 fSections.push_back(&fMachHeaderPseudoSection);
304
305 // get LC_DYLD_INFO
306 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
307 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
308 const uint32_t cmd_count = fHeader->ncmds();
309 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
310 const macho_load_command<P>* cmd = cmds;
311 for (uint32_t i = 0; i < cmd_count; ++i) {
312 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
313 if ( endOfCmd > endOfLoadCommands )
314 throwf("load command #%d extends beyond the end of the load commands", i);
315 if ( endOfCmd > endOfFile )
316 throwf("load command #%d extends beyond the end of the file", i);
317 switch ( cmd->cmd() ) {
318 case LC_DYLD_INFO:
319 case LC_DYLD_INFO_ONLY:
320 fInfo = (macho_dyld_info_command<P>*)cmd;
321 break;
322 case macho_segment_command<P>::CMD:
323 {
324 const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
325 fSegments.push_back(segCmd);
326 if ( (segCmd->fileoff() == 0) && (segCmd->filesize() != 0) )
327 fBaseAddress = segCmd->vmaddr();
328 if ( fFirstSegment == NULL )
329 fFirstSegment = segCmd;
330 if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) {
331 if ( fFirstWritableSegment == NULL )
332 fFirstWritableSegment = segCmd;
333 if ( segCmd->vmaddr() > 0x100000000ULL )
334 fWriteableSegmentWithAddrOver4G = true;
335 }
336 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
337 const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
338 for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect)
339 fSections.push_back(sect);
340 }
341 break;
342 case LC_LOAD_DYLIB:
343 case LC_LOAD_WEAK_DYLIB:
344 case LC_REEXPORT_DYLIB:
345 case LC_LOAD_UPWARD_DYLIB:
346 case LC_LAZY_LOAD_DYLIB:
347 {
348 const macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
349 fDylibLoadCommands.push_back(dylib);
350 const char* lastSlash = strrchr(dylib->name(), '/');
351 const char* leafName = (lastSlash != NULL) ? lastSlash+1 : dylib->name();
352 const char* firstDot = strchr(leafName, '.');
353 if ( firstDot != NULL ) {
354 char* t = strdup(leafName);
355 t[firstDot-leafName] = '\0';
356 fDylibs.push_back(t);
357 }
358 else {
359 fDylibs.push_back(leafName);
360 }
361 }
362 break;
363 case LC_DYSYMTAB:
364 fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
365 break;
366 case LC_SYMTAB:
367 {
368 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
369 fSymbolCount = symtab->nsyms();
370 fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
371 fStrings = (char*)fHeader + symtab->stroff();
372 fStringsEnd = fStrings + symtab->strsize();
373 }
374 break;
375 case LC_SEGMENT_SPLIT_INFO:
376 fSharedRegionInfo = (macho_linkedit_data_command<P>*)cmd;
377 break;
378 case LC_FUNCTION_STARTS:
379 fFunctionStartsInfo = (macho_linkedit_data_command<P>*)cmd;
380 break;
381 case LC_DATA_IN_CODE:
382 fDataInCode = (macho_linkedit_data_command<P>*)cmd;
383 break;
384 case LC_DYLIB_CODE_SIGN_DRS:
385 fDRInfo = (macho_linkedit_data_command<P>*)cmd;
386 break;
387 }
388 cmd = (const macho_load_command<P>*)endOfCmd;
389 }
390
391 if ( printArch ) {
392 for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
393 if ( (cpu_type_t)fHeader->cputype() == t->cpuType ) {
394 if ( t->isSubType && ((cpu_subtype_t)fHeader->cpusubtype() != t->cpuSubType) )
395 continue;
396 printf("for arch %s:\n", t->archName);
397 }
398 }
399 }
400
401 if ( printRebase ) {
402 if ( fInfo != NULL )
403 printRebaseInfo();
404 else
405 printRelocRebaseInfo();
406 }
407 if ( printBind ) {
408 if ( fInfo != NULL )
409 printBindingInfo();
410 else
411 printClassicBindingInfo();
412 }
413 if ( printWeakBind )
414 printWeakBindingInfo();
415 if ( printLazyBind ) {
416 if ( fInfo != NULL )
417 printLazyBindingInfo();
418 else
419 printClassicLazyBindingInfo();
420 }
421 if ( printExport ) {
422 if ( fInfo != NULL )
423 printExportInfo();
424 else
425 printSymbolTableExportInfo();
426 }
427 if ( printOpcodes ) {
428 printRebaseInfoOpcodes();
429 printBindingInfoOpcodes(false);
430 printBindingInfoOpcodes(true);
431 printLazyBindingOpcodes();
432 }
433 if ( printExportGraph )
434 printExportInfoGraph();
435 if ( printExportNodes )
436 printExportInfoNodes();
437 if ( printSharedRegion )
438 printSharedRegionInfo();
439 if ( printFunctionStarts )
440 printFunctionStartsInfo();
441 if ( printDylibs )
442 printDylibsInfo();
443 if ( printDRs )
444 printDRInfo();
445 if ( printDataCode )
446 printDataInCode();
447 }
448
449 static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
450 {
451 uint64_t result = 0;
452 int bit = 0;
453 do {
454 if (p == end)
455 throwf("malformed uleb128");
456
457 uint64_t slice = *p & 0x7f;
458
459 if (bit >= 64 || slice << bit >> bit != slice)
460 throwf("uleb128 too big");
461 else {
462 result |= (slice << bit);
463 bit += 7;
464 }
465 }
466 while (*p++ & 0x80);
467 return result;
468 }
469
470 static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
471 {
472 int64_t result = 0;
473 int bit = 0;
474 uint8_t byte;
475 do {
476 if (p == end)
477 throwf("malformed sleb128");
478 byte = *p++;
479 result |= (((int64_t)(byte & 0x7f)) << bit);
480 bit += 7;
481 } while (byte & 0x80);
482 // sign extend negative numbers
483 if ( (byte & 0x40) != 0 )
484 result |= (-1LL) << bit;
485 return result;
486 }
487
488
489 template <typename A>
490 const char* DyldInfoPrinter<A>::rebaseTypeName(uint8_t type)
491 {
492 switch (type ){
493 case REBASE_TYPE_POINTER:
494 return "pointer";
495 case REBASE_TYPE_TEXT_ABSOLUTE32:
496 return "text abs32";
497 case REBASE_TYPE_TEXT_PCREL32:
498 return "text rel32";
499 }
500 return "!!unknown!!";
501 }
502
503
504 template <typename A>
505 const char* DyldInfoPrinter<A>::bindTypeName(uint8_t type)
506 {
507 switch (type ){
508 case BIND_TYPE_POINTER:
509 return "pointer";
510 case BIND_TYPE_TEXT_ABSOLUTE32:
511 return "text abs32";
512 case BIND_TYPE_TEXT_PCREL32:
513 return "text rel32";
514 }
515 return "!!unknown!!";
516 }
517
518
519 template <typename A>
520 typename A::P::uint_t DyldInfoPrinter<A>::segStartAddress(uint8_t segIndex)
521 {
522 if ( segIndex > fSegments.size() )
523 throw "segment index out of range";
524 return fSegments[segIndex]->vmaddr();
525 }
526
527 template <typename A>
528 const char* DyldInfoPrinter<A>::segmentName(uint8_t segIndex)
529 {
530 if ( segIndex > fSegments.size() )
531 throw "segment index out of range";
532 return fSegments[segIndex]->segname();
533 }
534
535 template <typename A>
536 const char* DyldInfoPrinter<A>::sectionName(uint8_t segIndex, pint_t address)
537 {
538 if ( segIndex > fSegments.size() )
539 throw "segment index out of range";
540 const macho_segment_command<P>* segCmd = fSegments[segIndex];
541 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
542 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
543 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
544 if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
545 if ( strlen(sect->sectname()) > 15 ) {
546 static char temp[18];
547 strlcpy(temp, sect->sectname(), 17);
548 return temp;
549 }
550 else {
551 return sect->sectname();
552 }
553 }
554 }
555 return "??";
556 }
557
558 template <typename A>
559 const char* DyldInfoPrinter<A>::getSegAndSectName(uint8_t segIndex, pint_t address)
560 {
561 static char buffer[64];
562 strcpy(buffer, segmentName(segIndex));
563 strcat(buffer, "/");
564 const macho_segment_command<P>* segCmd = fSegments[segIndex];
565 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
566 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
567 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
568 if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
569 // section name may not be zero terminated
570 char* end = &buffer[strlen(buffer)];
571 strlcpy(end, sect->sectname(), 16);
572 return buffer;
573 }
574 }
575 return "??";
576 }
577
578 template <typename A>
579 uint8_t DyldInfoPrinter<A>::segmentIndexForAddress(pint_t address)
580 {
581 for(unsigned int i=0; i < fSegments.size(); ++i) {
582 if ( (fSegments[i]->vmaddr() <= address) && (address < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) {
583 return i;
584 }
585 }
586 throwf("address 0x%llX is not in any segment", (uint64_t)address);
587 }
588
589 template <typename A>
590 typename A::P::uint_t* DyldInfoPrinter<A>::mappedAddressForVMAddress(pint_t vmaddress)
591 {
592 for(unsigned int i=0; i < fSegments.size(); ++i) {
593 if ( (fSegments[i]->vmaddr() <= vmaddress) && (vmaddress < (fSegments[i]->vmaddr()+fSegments[i]->vmsize())) ) {
594 unsigned long offsetInMappedFile = fSegments[i]->fileoff()+vmaddress-fSegments[i]->vmaddr();
595 return (pint_t*)((uint8_t*)fHeader + offsetInMappedFile);
596 }
597 }
598 throwf("address 0x%llX is not in any segment", (uint64_t)vmaddress);
599 }
600
601 template <typename A>
602 const char* DyldInfoPrinter<A>::ordinalName(int libraryOrdinal)
603 {
604 switch ( libraryOrdinal) {
605 case BIND_SPECIAL_DYLIB_SELF:
606 return "this-image";
607 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
608 return "main-executable";
609 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
610 return "flat-namespace";
611 }
612 if ( libraryOrdinal < BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
613 throw "unknown special ordinal";
614 if ( libraryOrdinal > (int)fDylibs.size() )
615 throw "libraryOrdinal out of range";
616 return fDylibs[libraryOrdinal-1];
617 }
618
619 template <typename A>
620 const char* DyldInfoPrinter<A>::classicOrdinalName(int libraryOrdinal)
621 {
622 if ( (fHeader->flags() & MH_TWOLEVEL) == 0 )
623 return "flat-namespace";
624 switch ( libraryOrdinal) {
625 case SELF_LIBRARY_ORDINAL:
626 return "this-image";
627 case EXECUTABLE_ORDINAL:
628 return "main-executable";
629 case DYNAMIC_LOOKUP_ORDINAL:
630 return "flat-namespace";
631 }
632 if ( libraryOrdinal > (int)fDylibs.size() )
633 throw "libraryOrdinal out of range";
634 return fDylibs[libraryOrdinal-1];
635 }
636
637 template <typename A>
638 void DyldInfoPrinter<A>::printRebaseInfo()
639 {
640 if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
641 printf("no compressed rebase info\n");
642 }
643 else {
644 printf("rebase information (from compressed dyld info):\n");
645 printf("segment section address type\n");
646
647 const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
648 const uint8_t* end = &p[fInfo->rebase_size()];
649
650 uint8_t type = 0;
651 uint64_t segOffset = 0;
652 uint32_t count;
653 uint32_t skip;
654 int segIndex = 0;
655 pint_t segStartAddr = 0;
656 const char* segName = "??";
657 const char* typeName = "??";
658 bool done = false;
659 while ( !done && (p < end) ) {
660 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
661 uint8_t opcode = *p & REBASE_OPCODE_MASK;
662 ++p;
663 switch (opcode) {
664 case REBASE_OPCODE_DONE:
665 done = true;
666 break;
667 case REBASE_OPCODE_SET_TYPE_IMM:
668 type = immediate;
669 typeName = rebaseTypeName(type);
670 break;
671 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
672 segIndex = immediate;
673 segStartAddr = segStartAddress(segIndex);
674 segName = segmentName(segIndex);
675 segOffset = read_uleb128(p, end);
676 break;
677 case REBASE_OPCODE_ADD_ADDR_ULEB:
678 segOffset += read_uleb128(p, end);
679 break;
680 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
681 segOffset += immediate*sizeof(pint_t);
682 break;
683 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
684 for (int i=0; i < immediate; ++i) {
685 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
686 segOffset += sizeof(pint_t);
687 }
688 break;
689 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
690 count = read_uleb128(p, end);
691 for (uint32_t i=0; i < count; ++i) {
692 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
693 segOffset += sizeof(pint_t);
694 }
695 break;
696 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
697 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
698 segOffset += read_uleb128(p, end) + sizeof(pint_t);
699 break;
700 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
701 count = read_uleb128(p, end);
702 skip = read_uleb128(p, end);
703 for (uint32_t i=0; i < count; ++i) {
704 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
705 segOffset += skip + sizeof(pint_t);
706 }
707 break;
708 default:
709 throwf("bad rebase opcode %d", *p);
710 }
711 }
712 }
713
714 }
715
716
717
718 template <typename A>
719 void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
720 {
721 if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
722 printf("no compressed rebase info\n");
723 }
724 else {
725 printf("rebase opcodes:\n");
726 const uint8_t* start = (uint8_t*)fHeader + fInfo->rebase_off();
727 const uint8_t* end = &start[fInfo->rebase_size()];
728 const uint8_t* p = start;
729
730 uint8_t type = 0;
731 uint64_t address = fBaseAddress;
732 uint32_t count;
733 uint32_t skip;
734 unsigned int segmentIndex;
735 bool done = false;
736 while ( !done && (p < end) ) {
737 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
738 uint8_t opcode = *p & REBASE_OPCODE_MASK;
739 uint32_t opcodeOffset = p-start;
740 ++p;
741 switch (opcode) {
742 case REBASE_OPCODE_DONE:
743 done = true;
744 printf("0x%04X REBASE_OPCODE_DONE()\n", opcodeOffset);
745 break;
746 case REBASE_OPCODE_SET_TYPE_IMM:
747 type = immediate;
748 printf("0x%04X REBASE_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
749 break;
750 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
751 segmentIndex = immediate;
752 address = read_uleb128(p, end);
753 printf("0x%04X REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
754 break;
755 case REBASE_OPCODE_ADD_ADDR_ULEB:
756 address = read_uleb128(p, end);
757 printf("0x%04X REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", opcodeOffset, address);
758 break;
759 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
760 address = immediate*sizeof(pint_t);
761 printf("0x%04X REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", opcodeOffset, address);
762 break;
763 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
764 printf("0x%04X REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", opcodeOffset, immediate);
765 break;
766 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
767 count = read_uleb128(p, end);
768 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", opcodeOffset, count);
769 break;
770 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
771 skip = read_uleb128(p, end) + sizeof(pint_t);
772 printf("0x%04X REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", opcodeOffset, skip);
773 break;
774 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
775 count = read_uleb128(p, end);
776 skip = read_uleb128(p, end);
777 printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", opcodeOffset, count, skip);
778 break;
779 default:
780 throwf("bad rebase opcode %d", *p);
781 }
782 }
783 }
784
785 }
786
787
788
789
790
791
792 template <typename A>
793 void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
794 {
795 if ( fInfo == NULL ) {
796 printf("no compressed binding info\n");
797 }
798 else if ( !weakbinding && (fInfo->bind_off() == 0) ) {
799 printf("no compressed binding info\n");
800 }
801 else if ( weakbinding && (fInfo->weak_bind_off() == 0) ) {
802 printf("no compressed weak binding info\n");
803 }
804 else {
805 const uint8_t* start;
806 const uint8_t* end;
807 if ( weakbinding ) {
808 printf("weak binding opcodes:\n");
809 start = (uint8_t*)fHeader + fInfo->weak_bind_off();
810 end = &start[fInfo->weak_bind_size()];
811 }
812 else {
813 printf("binding opcodes:\n");
814 start = (uint8_t*)fHeader + fInfo->bind_off();
815 end = &start[fInfo->bind_size()];
816 }
817 const uint8_t* p = start;
818 uint8_t type = 0;
819 uint8_t flags;
820 uint64_t address = fBaseAddress;
821 const char* symbolName = NULL;
822 int libraryOrdinal = 0;
823 int64_t addend = 0;
824 uint32_t segmentIndex = 0;
825 uint32_t count;
826 uint32_t skip;
827 bool done = false;
828 while ( !done && (p < end) ) {
829 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
830 uint8_t opcode = *p & BIND_OPCODE_MASK;
831 uint32_t opcodeOffset = p-start;
832 ++p;
833 switch (opcode) {
834 case BIND_OPCODE_DONE:
835 done = true;
836 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
837 break;
838 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
839 libraryOrdinal = immediate;
840 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
841 break;
842 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
843 libraryOrdinal = read_uleb128(p, end);
844 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
845 break;
846 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
847 // the special ordinals are negative numbers
848 if ( immediate == 0 )
849 libraryOrdinal = 0;
850 else {
851 int8_t signExtended = BIND_OPCODE_MASK | immediate;
852 libraryOrdinal = signExtended;
853 }
854 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
855 break;
856 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
857 flags = immediate;
858 symbolName = (char*)p;
859 while (*p != '\0')
860 ++p;
861 ++p;
862 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
863 break;
864 case BIND_OPCODE_SET_TYPE_IMM:
865 type = immediate;
866 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
867 break;
868 case BIND_OPCODE_SET_ADDEND_SLEB:
869 addend = read_sleb128(p, end);
870 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
871 break;
872 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
873 segmentIndex = immediate;
874 address = read_uleb128(p, end);
875 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
876 break;
877 case BIND_OPCODE_ADD_ADDR_ULEB:
878 skip = read_uleb128(p, end);
879 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
880 break;
881 case BIND_OPCODE_DO_BIND:
882 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
883 break;
884 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
885 skip = read_uleb128(p, end);
886 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
887 break;
888 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
889 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
890 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
891 break;
892 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
893 count = read_uleb128(p, end);
894 skip = read_uleb128(p, end);
895 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
896 break;
897 default:
898 throwf("unknown bind opcode %d", *p);
899 }
900 }
901 }
902
903 }
904
905
906
907 template <typename A>
908 void DyldInfoPrinter<A>::printBindingInfo()
909 {
910 if ( (fInfo == NULL) || (fInfo->bind_off() == 0) ) {
911 printf("no compressed binding info\n");
912 }
913 else {
914 printf("bind information:\n");
915 printf("segment section address type addend dylib symbol\n");
916 const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
917 const uint8_t* end = &p[fInfo->bind_size()];
918
919 uint8_t type = 0;
920 uint8_t segIndex = 0;
921 uint64_t segOffset = 0;
922 const char* symbolName = NULL;
923 const char* fromDylib = "??";
924 int libraryOrdinal = 0;
925 int64_t addend = 0;
926 uint32_t count;
927 uint32_t skip;
928 pint_t segStartAddr = 0;
929 const char* segName = "??";
930 const char* typeName = "??";
931 const char* weak_import = "";
932 bool done = false;
933 while ( !done && (p < end) ) {
934 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
935 uint8_t opcode = *p & BIND_OPCODE_MASK;
936 ++p;
937 switch (opcode) {
938 case BIND_OPCODE_DONE:
939 done = true;
940 break;
941 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
942 libraryOrdinal = immediate;
943 fromDylib = ordinalName(libraryOrdinal);
944 break;
945 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
946 libraryOrdinal = read_uleb128(p, end);
947 fromDylib = ordinalName(libraryOrdinal);
948 break;
949 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
950 // the special ordinals are negative numbers
951 if ( immediate == 0 )
952 libraryOrdinal = 0;
953 else {
954 int8_t signExtended = BIND_OPCODE_MASK | immediate;
955 libraryOrdinal = signExtended;
956 }
957 fromDylib = ordinalName(libraryOrdinal);
958 break;
959 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
960 symbolName = (char*)p;
961 while (*p != '\0')
962 ++p;
963 ++p;
964 if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
965 weak_import = " (weak import)";
966 else
967 weak_import = "";
968 break;
969 case BIND_OPCODE_SET_TYPE_IMM:
970 type = immediate;
971 typeName = bindTypeName(type);
972 break;
973 case BIND_OPCODE_SET_ADDEND_SLEB:
974 addend = read_sleb128(p, end);
975 break;
976 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
977 segIndex = immediate;
978 segStartAddr = segStartAddress(segIndex);
979 segName = segmentName(segIndex);
980 segOffset = read_uleb128(p, end);
981 break;
982 case BIND_OPCODE_ADD_ADDR_ULEB:
983 segOffset += read_uleb128(p, end);
984 break;
985 case BIND_OPCODE_DO_BIND:
986 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
987 segOffset += sizeof(pint_t);
988 break;
989 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
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 += read_uleb128(p, end) + sizeof(pint_t);
992 break;
993 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
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 += immediate*sizeof(pint_t) + sizeof(pint_t);
996 break;
997 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
998 count = read_uleb128(p, end);
999 skip = read_uleb128(p, end);
1000 for (uint32_t i=0; i < count; ++i) {
1001 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
1002 segOffset += skip + sizeof(pint_t);
1003 }
1004 break;
1005 default:
1006 throwf("bad bind opcode %d", *p);
1007 }
1008 }
1009 }
1010
1011 }
1012
1013 template <typename A>
1014 void DyldInfoPrinter<A>::printWeakBindingInfo()
1015 {
1016 if ( (fInfo == NULL) || (fInfo->weak_bind_off() == 0) ) {
1017 printf("no weak binding\n");
1018 }
1019 else {
1020 printf("weak binding information:\n");
1021 printf("segment section address type addend symbol\n");
1022 const uint8_t* p = (uint8_t*)fHeader + fInfo->weak_bind_off();
1023 const uint8_t* end = &p[fInfo->weak_bind_size()];
1024
1025 uint8_t type = 0;
1026 uint8_t segIndex = 0;
1027 uint64_t segOffset = 0;
1028 const char* symbolName = NULL;
1029 int64_t addend = 0;
1030 uint32_t count;
1031 uint32_t skip;
1032 pint_t segStartAddr = 0;
1033 const char* segName = "??";
1034 const char* typeName = "??";
1035 bool done = false;
1036 while ( !done && (p < end) ) {
1037 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1038 uint8_t opcode = *p & BIND_OPCODE_MASK;
1039 ++p;
1040 switch (opcode) {
1041 case BIND_OPCODE_DONE:
1042 done = true;
1043 break;
1044 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1045 symbolName = (char*)p;
1046 while (*p != '\0')
1047 ++p;
1048 ++p;
1049 if ( (immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) != 0 )
1050 printf(" strong %s\n", symbolName );
1051 break;
1052 case BIND_OPCODE_SET_TYPE_IMM:
1053 type = immediate;
1054 typeName = bindTypeName(type);
1055 break;
1056 case BIND_OPCODE_SET_ADDEND_SLEB:
1057 addend = read_sleb128(p, end);
1058 break;
1059 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1060 segIndex = immediate;
1061 segStartAddr = segStartAddress(segIndex);
1062 segName = segmentName(segIndex);
1063 segOffset = read_uleb128(p, end);
1064 break;
1065 case BIND_OPCODE_ADD_ADDR_ULEB:
1066 segOffset += read_uleb128(p, end);
1067 break;
1068 case BIND_OPCODE_DO_BIND:
1069 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
1070 segOffset += sizeof(pint_t);
1071 break;
1072 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1073 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
1074 segOffset += read_uleb128(p, end) + sizeof(pint_t);
1075 break;
1076 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1077 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
1078 segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
1079 break;
1080 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1081 count = read_uleb128(p, end);
1082 skip = read_uleb128(p, end);
1083 for (uint32_t i=0; i < count; ++i) {
1084 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
1085 segOffset += skip + sizeof(pint_t);
1086 }
1087 break;
1088 default:
1089 throwf("unknown weak bind opcode %d", *p);
1090 }
1091 }
1092 }
1093
1094 }
1095
1096
1097 template <typename A>
1098 void DyldInfoPrinter<A>::printLazyBindingInfo()
1099 {
1100 if ( fInfo == NULL ) {
1101 printf("no compressed dyld info\n");
1102 }
1103 else if ( fInfo->lazy_bind_off() == 0 ) {
1104 printf("no compressed lazy binding info\n");
1105 }
1106 else {
1107 printf("lazy binding information (from lazy_bind part of dyld info):\n");
1108 printf("segment section address index dylib symbol\n");
1109 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
1110 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
1111
1112 uint8_t type = BIND_TYPE_POINTER;
1113 uint8_t segIndex = 0;
1114 uint64_t segOffset = 0;
1115 const char* symbolName = NULL;
1116 const char* fromDylib = "??";
1117 int libraryOrdinal = 0;
1118 int64_t addend = 0;
1119 uint32_t lazy_offset = 0;
1120 pint_t segStartAddr = 0;
1121 const char* segName = "??";
1122 const char* typeName = "??";
1123 const char* weak_import = "";
1124 for (const uint8_t* p=start; p < end; ) {
1125 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1126 uint8_t opcode = *p & BIND_OPCODE_MASK;
1127 ++p;
1128 switch (opcode) {
1129 case BIND_OPCODE_DONE:
1130 lazy_offset = p-start;
1131 break;
1132 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1133 libraryOrdinal = immediate;
1134 fromDylib = ordinalName(libraryOrdinal);
1135 break;
1136 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1137 libraryOrdinal = read_uleb128(p, end);
1138 fromDylib = ordinalName(libraryOrdinal);
1139 break;
1140 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1141 // the special ordinals are negative numbers
1142 if ( immediate == 0 )
1143 libraryOrdinal = 0;
1144 else {
1145 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1146 libraryOrdinal = signExtended;
1147 }
1148 fromDylib = ordinalName(libraryOrdinal);
1149 break;
1150 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1151 symbolName = (char*)p;
1152 while (*p != '\0')
1153 ++p;
1154 ++p;
1155 if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
1156 weak_import = " (weak import)";
1157 else
1158 weak_import = "";
1159 break;
1160 case BIND_OPCODE_SET_TYPE_IMM:
1161 type = immediate;
1162 typeName = bindTypeName(type);
1163 break;
1164 case BIND_OPCODE_SET_ADDEND_SLEB:
1165 addend = read_sleb128(p, end);
1166 break;
1167 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1168 segIndex = immediate;
1169 segStartAddr = segStartAddress(segIndex);
1170 segName = segmentName(segIndex);
1171 segOffset = read_uleb128(p, end);
1172 break;
1173 case BIND_OPCODE_ADD_ADDR_ULEB:
1174 segOffset += read_uleb128(p, end);
1175 break;
1176 case BIND_OPCODE_DO_BIND:
1177 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName, weak_import);
1178 segOffset += sizeof(pint_t);
1179 break;
1180 default:
1181 throwf("bad lazy bind opcode %d", *p);
1182 }
1183 }
1184 }
1185
1186 }
1187
1188 template <typename A>
1189 void DyldInfoPrinter<A>::printLazyBindingOpcodes()
1190 {
1191 if ( fInfo == NULL ) {
1192 printf("no compressed dyld info\n");
1193 }
1194 else if ( fInfo->lazy_bind_off() == 0 ) {
1195 printf("no compressed lazy binding info\n");
1196 }
1197 else {
1198 printf("lazy binding opcodes:\n");
1199 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
1200 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
1201 uint8_t type = BIND_TYPE_POINTER;
1202 uint8_t flags;
1203 uint64_t address = fBaseAddress;
1204 const char* symbolName = NULL;
1205 int libraryOrdinal = 0;
1206 int64_t addend = 0;
1207 uint32_t segmentIndex = 0;
1208 uint32_t count;
1209 uint32_t skip;
1210 for (const uint8_t* p = start; p < end; ) {
1211 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1212 uint8_t opcode = *p & BIND_OPCODE_MASK;
1213 uint32_t opcodeOffset = p-start;
1214 ++p;
1215 switch (opcode) {
1216 case BIND_OPCODE_DONE:
1217 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
1218 break;
1219 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1220 libraryOrdinal = immediate;
1221 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1222 break;
1223 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1224 libraryOrdinal = read_uleb128(p, end);
1225 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
1226 break;
1227 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1228 // the special ordinals are negative numbers
1229 if ( immediate == 0 )
1230 libraryOrdinal = 0;
1231 else {
1232 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1233 libraryOrdinal = signExtended;
1234 }
1235 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1236 break;
1237 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1238 flags = immediate;
1239 symbolName = (char*)p;
1240 while (*p != '\0')
1241 ++p;
1242 ++p;
1243 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
1244 break;
1245 case BIND_OPCODE_SET_TYPE_IMM:
1246 type = immediate;
1247 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
1248 break;
1249 case BIND_OPCODE_SET_ADDEND_SLEB:
1250 addend = read_sleb128(p, end);
1251 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
1252 break;
1253 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1254 segmentIndex = immediate;
1255 address = read_uleb128(p, end);
1256 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
1257 break;
1258 case BIND_OPCODE_ADD_ADDR_ULEB:
1259 skip = read_uleb128(p, end);
1260 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1261 break;
1262 case BIND_OPCODE_DO_BIND:
1263 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
1264 break;
1265 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1266 skip = read_uleb128(p, end);
1267 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1268 break;
1269 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1270 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
1271 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
1272 break;
1273 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1274 count = read_uleb128(p, end);
1275 skip = read_uleb128(p, end);
1276 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
1277 break;
1278 default:
1279 throwf("unknown bind opcode %d", *p);
1280 }
1281 }
1282 }
1283
1284 }
1285
1286 struct SortExportsByAddress
1287 {
1288 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
1289 {
1290 return ( left.address < right.address );
1291 }
1292 };
1293
1294 template <typename A>
1295 void DyldInfoPrinter<A>::printExportInfo()
1296 {
1297 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1298 printf("no compressed export info\n");
1299 }
1300 else {
1301 printf("export information (from trie):\n");
1302 const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
1303 const uint8_t* end = &start[fInfo->export_size()];
1304 std::vector<mach_o::trie::Entry> list;
1305 parseTrie(start, end, list);
1306 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1307 for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) {
1308 const bool reExport = (it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT);
1309 const bool weakDef = (it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
1310 const bool threadLocal = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
1311 const bool abs = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
1312 const bool resolver = (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
1313 if ( reExport )
1314 printf("[re-export] ");
1315 else
1316 printf("0x%08llX ", fBaseAddress+it->address);
1317 printf("%s", it->name);
1318 if ( weakDef || threadLocal || resolver || abs ) {
1319 bool needComma = false;
1320 printf(" [");
1321 if ( weakDef ) {
1322 printf("weak_def");
1323 needComma = true;
1324 }
1325 if ( threadLocal ) {
1326 if ( needComma )
1327 printf(", ");
1328 printf("per-thread");
1329 needComma = true;
1330 }
1331 if ( abs ) {
1332 if ( needComma )
1333 printf(", ");
1334 printf("absolute");
1335 needComma = true;
1336 }
1337 if ( resolver ) {
1338 if ( needComma )
1339 printf(", ");
1340 printf("resolver=0x%08llX", it->other);
1341 needComma = true;
1342 }
1343 printf("]");
1344 }
1345 if ( reExport ) {
1346 if ( it->importName[0] == '\0' )
1347 printf(" (from %s)", fDylibs[it->other - 1]);
1348 else
1349 printf(" (%s from %s)", it->importName, fDylibs[it->other - 1]);
1350 }
1351 printf("\n");
1352 }
1353 }
1354 }
1355
1356
1357 template <typename A>
1358 void DyldInfoPrinter<A>::processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
1359 const uint8_t* parent, const uint8_t* p,
1360 char* cummulativeString, int curStrOffset)
1361 {
1362 const uint8_t* const me = p;
1363 const uint64_t terminalSize = read_uleb128(p, end);
1364 const uint8_t* children = p + terminalSize;
1365 if ( terminalSize != 0 ) {
1366 uint32_t flags = read_uleb128(p, end);
1367 if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
1368 uint64_t ordinal = read_uleb128(p, end);
1369 const char* importName = (const char*)p;
1370 while (*p != '\0')
1371 ++p;
1372 ++p;
1373 if ( *importName == '\0' )
1374 printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me-start), cummulativeString, ordinal);
1375 else
1376 printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me-start), cummulativeString, importName, ordinal);
1377 }
1378 else {
1379 uint64_t address = read_uleb128(p, end);
1380 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address);
1381 if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
1382 read_uleb128(p, end);
1383 }
1384 }
1385 else {
1386 printf("\tnode%03ld;\n", (long)(me-start));
1387 }
1388 const uint8_t childrenCount = *children++;
1389 const uint8_t* s = children;
1390 for (uint8_t i=0; i < childrenCount; ++i) {
1391 const char* edgeName = (char*)s;
1392 int edgeStrLen = 0;
1393 while (*s != '\0') {
1394 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1395 ++edgeStrLen;
1396 }
1397 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1398 uint32_t childNodeOffet = read_uleb128(s, end);
1399 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me-start), childNodeOffet, edgeName);
1400 processExportGraphNode(start, end, start, start+childNodeOffet, cummulativeString, curStrOffset+edgeStrLen);
1401 }
1402 }
1403
1404 template <typename A>
1405 void DyldInfoPrinter<A>::printExportInfoGraph()
1406 {
1407 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1408 printf("no compressed export info\n");
1409 }
1410 else {
1411 const uint8_t* p = (uint8_t*)fHeader + fInfo->export_off();
1412 const uint8_t* end = &p[fInfo->export_size()];
1413 char cummulativeString[2000];
1414 printf("digraph {\n");
1415 processExportGraphNode(p, end, p, p, cummulativeString, 0);
1416 printf("}\n");
1417 }
1418 }
1419
1420 template <typename A>
1421 void DyldInfoPrinter<A>::gatherNodeStarts(const uint8_t* const start, const uint8_t* const end,
1422 const uint8_t* parent, const uint8_t* p,
1423 std::vector<uint32_t>& nodeStarts)
1424 {
1425 nodeStarts.push_back(p-start);
1426 const uint8_t terminalSize = read_uleb128(p, end);
1427 const uint8_t* children = p + terminalSize;
1428
1429 const uint8_t childrenCount = *children++;
1430 const uint8_t* s = children;
1431 for (uint8_t i=0; i < childrenCount; ++i) {
1432 // skip over edge string
1433 while (*s != '\0')
1434 ++s;
1435 ++s;
1436 uint32_t childNodeOffet = read_uleb128(s, end);
1437 gatherNodeStarts(start, end, start, start+childNodeOffet, nodeStarts);
1438 }
1439 }
1440
1441
1442 template <typename A>
1443 void DyldInfoPrinter<A>::printExportInfoNodes()
1444 {
1445 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1446 printf("no compressed export info\n");
1447 }
1448 else {
1449 const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
1450 const uint8_t* end = &start[fInfo->export_size()];
1451 std::vector<uint32_t> nodeStarts;
1452 gatherNodeStarts(start, end, start, start, nodeStarts);
1453 std::sort(nodeStarts.begin(), nodeStarts.end());
1454 for (std::vector<uint32_t>::const_iterator it=nodeStarts.begin(); it != nodeStarts.end(); ++it) {
1455 printf("0x%04X: ", *it);
1456 const uint8_t* p = start + *it;
1457 uint64_t exportInfoSize = read_uleb128(p, end);
1458 if ( exportInfoSize != 0 ) {
1459 // print terminal info
1460 uint64_t flags = read_uleb128(p, end);
1461 if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
1462 uint64_t ordinal = read_uleb128(p, end);
1463 const char* importName = (const char*)p;
1464 while (*p != '\0')
1465 ++p;
1466 ++p;
1467 if ( strlen(importName) == 0 )
1468 printf("[flags=REEXPORT ordinal=%llu] ", ordinal);
1469 else
1470 printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal, importName);
1471 }
1472 else if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
1473 uint64_t stub = read_uleb128(p, end);
1474 uint64_t resolver = read_uleb128(p, end);
1475 printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub, resolver);
1476 }
1477 else {
1478 uint64_t address = read_uleb128(p, end);
1479 if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR )
1480 printf("[addr=0x%06llX] ", address);
1481 else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)
1482 printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address);
1483 else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE)
1484 printf("[flags=ABSOLUTE addr=0x%06llX] ", address);
1485 else
1486 printf("[flags=0x%llX addr=0x%06llX] ", flags, address);
1487 }
1488 }
1489 // print child edges
1490 const uint8_t childrenCount = *p++;
1491 for (uint8_t i=0; i < childrenCount; ++i) {
1492 const char* edgeName = (const char*)p;
1493 while (*p != '\0')
1494 ++p;
1495 ++p;
1496 uint32_t childNodeOffet = read_uleb128(p, end);
1497 printf("%s->0x%04X", edgeName, childNodeOffet);
1498 if ( i < (childrenCount-1) )
1499 printf(", ");
1500 }
1501 printf("\n");
1502 }
1503 }
1504 }
1505
1506
1507
1508 template <typename A>
1509 const uint8_t* DyldInfoPrinter<A>::printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end, uint8_t kind)
1510 {
1511 const char* kindStr = "??";
1512 switch (kind ) {
1513 case DYLD_CACHE_ADJ_V1_POINTER_32:
1514 kindStr = "32-bit pointer";
1515 break;
1516 case DYLD_CACHE_ADJ_V1_POINTER_64:
1517 kindStr = "64-bit pointer";
1518 break;
1519 case DYLD_CACHE_ADJ_V1_ADRP:
1520 kindStr = "arm64 ADRP";
1521 break;
1522 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+0:
1523 kindStr = "thumb2 movt low high 4 bits=0";
1524 break;
1525 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+1:
1526 kindStr = "thumb2 movt low high 4 bits=1";
1527 break;
1528 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+2:
1529 kindStr = "thumb2 movt low high 4 bits=2";
1530 break;
1531 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+3:
1532 kindStr = "thumb2 movt low high 4 bits=3";
1533 break;
1534 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+4:
1535 kindStr = "thumb2 movt low high 4 bits=4";
1536 break;
1537 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+5:
1538 kindStr = "thumb2 movt low high 4 bits=5";
1539 break;
1540 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+6:
1541 kindStr = "thumb2 movt low high 4 bits=6";
1542 break;
1543 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+7:
1544 kindStr = "thumb2 movt low high 4 bits=7";
1545 break;
1546 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+8:
1547 kindStr = "thumb2 movt low high 4 bits=8";
1548 break;
1549 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+9:
1550 kindStr = "thumb2 movt low high 4 bits=9";
1551 break;
1552 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+10:
1553 kindStr = "thumb2 movt low high 4 bits=10";
1554 break;
1555 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+11:
1556 kindStr = "thumb2 movt low high 4 bits=11";
1557 break;
1558 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+12:
1559 kindStr = "thumb2 movt low high 4 bits=12";
1560 break;
1561 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+13:
1562 kindStr = "thumb2 movt low high 4 bits=13";
1563 break;
1564 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+14:
1565 kindStr = "thumb2 movt low high 4 bits=14";
1566 break;
1567 case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+15:
1568 kindStr = "thumb2 movt low high 4 bits=15";
1569 break;
1570 case DYLD_CACHE_ADJ_V1_ARM_MOVT+0:
1571 kindStr = "arm movt low high 4 bits=0";
1572 break;
1573 case DYLD_CACHE_ADJ_V1_ARM_MOVT+1:
1574 kindStr = "arm movt low high 4 bits=1";
1575 break;
1576 case DYLD_CACHE_ADJ_V1_ARM_MOVT+2:
1577 kindStr = "arm movt low high 4 bits=2";
1578 break;
1579 case DYLD_CACHE_ADJ_V1_ARM_MOVT+3:
1580 kindStr = "arm movt low high 4 bits=3";
1581 break;
1582 case DYLD_CACHE_ADJ_V1_ARM_MOVT+4:
1583 kindStr = "arm movt low high 4 bits=4";
1584 break;
1585 case DYLD_CACHE_ADJ_V1_ARM_MOVT+5:
1586 kindStr = "arm movt low high 4 bits=5";
1587 break;
1588 case DYLD_CACHE_ADJ_V1_ARM_MOVT+6:
1589 kindStr = "arm movt low high 4 bits=6";
1590 break;
1591 case DYLD_CACHE_ADJ_V1_ARM_MOVT+7:
1592 kindStr = "arm movt low high 4 bits=7";
1593 break;
1594 case DYLD_CACHE_ADJ_V1_ARM_MOVT+8:
1595 kindStr = "arm movt low high 4 bits=8";
1596 break;
1597 case DYLD_CACHE_ADJ_V1_ARM_MOVT+9:
1598 kindStr = "arm movt low high 4 bits=9";
1599 break;
1600 case DYLD_CACHE_ADJ_V1_ARM_MOVT+10:
1601 kindStr = "arm movt low high 4 bits=10";
1602 break;
1603 case DYLD_CACHE_ADJ_V1_ARM_MOVT+11:
1604 kindStr = "arm movt low high 4 bits=11";
1605 break;
1606 case DYLD_CACHE_ADJ_V1_ARM_MOVT+12:
1607 kindStr = "arm movt low high 4 bits=12";
1608 break;
1609 case DYLD_CACHE_ADJ_V1_ARM_MOVT+13:
1610 kindStr = "arm movt low high 4 bits=13";
1611 break;
1612 case DYLD_CACHE_ADJ_V1_ARM_MOVT+14:
1613 kindStr = "arm movt low high 4 bits=14";
1614 break;
1615 case DYLD_CACHE_ADJ_V1_ARM_MOVT+15:
1616 kindStr = "arm movt low high 4 bits=15";
1617 break;
1618 default:
1619 kindStr = "<<unknown>>";
1620 }
1621 uint64_t address = 0;
1622 uint64_t delta = 0;
1623 do {
1624 delta = read_uleb128(p, end);
1625 address += delta;
1626 printf("0x%0llX %s\n", address+fBaseAddress, kindStr);
1627 } while (delta);
1628
1629 return p;
1630 }
1631
1632 template <typename A>
1633 void DyldInfoPrinter<A>::printSharedRegionInfo()
1634 {
1635 if ( (fSharedRegionInfo == NULL) || (fSharedRegionInfo->datasize() == 0) ) {
1636 printf("no shared region info\n");
1637 }
1638 else {
1639 const uint8_t* infoStart = (uint8_t*)fHeader + fSharedRegionInfo->dataoff();
1640 const uint8_t* infoEnd = &infoStart[fSharedRegionInfo->datasize()];
1641 if ( *infoStart == DYLD_CACHE_ADJ_V2_FORMAT ) {
1642 ++infoStart;
1643 // Whole :== <count> FromToSection+
1644 // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
1645 // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
1646 // FromOffset :== <kind> <count> <from-sect-offset-delta>
1647 const uint8_t* p = infoStart;
1648 uint64_t sectionCount = read_uleb128(p, infoEnd);
1649 for (uint64_t i=0; i < sectionCount; ++i) {
1650 uint64_t fromSectionIndex = read_uleb128(p, infoEnd);
1651 uint64_t toSectionIndex = read_uleb128(p, infoEnd);
1652 uint64_t toOffsetCount = read_uleb128(p, infoEnd);
1653 const macho_section<P>* fromSection = fSections[fromSectionIndex];
1654 const macho_section<P>* toSection = fSections[toSectionIndex];
1655 printf("from sect=%s, to sect=%s, count=%lld:\n", fromSection->sectname(), toSection->sectname(), toOffsetCount);
1656 uint64_t toSectionOffset = 0;
1657 const char* lastFromSymbol = NULL;
1658 for (uint64_t j=0; j < toOffsetCount; ++j) {
1659 uint64_t toSectionDelta = read_uleb128(p, infoEnd);
1660 uint64_t fromOffsetCount = read_uleb128(p, infoEnd);
1661 toSectionOffset += toSectionDelta;
1662 for (uint64_t k=0; k < fromOffsetCount; ++k) {
1663 uint64_t kind = read_uleb128(p, infoEnd);
1664 uint64_t fromSectDeltaCount = read_uleb128(p, infoEnd);
1665 uint64_t fromSectionOffset = 0;
1666 for (uint64_t l=0; l < fromSectDeltaCount; ++l) {
1667 uint64_t delta = read_uleb128(p, infoEnd);
1668 fromSectionOffset += delta;
1669 uint64_t symbolOffset;
1670 const char* s = closestSymbolNameForAddress(fromSection->addr()+fromSectionOffset, &symbolOffset, fromSectionIndex);
1671 if ( (s != lastFromSymbol) && (s != NULL) )
1672 printf(" %s:\n", s);
1673 const char* toSymbol = closestSymbolNameForAddress(toSection->addr()+toSectionOffset, &symbolOffset, toSectionIndex);
1674 printf(" from addr=0x%0llX %s to addr=0x%0llX", fromSection->addr()+fromSectionOffset, sharedRegionKindName(kind), toSection->addr()+toSectionOffset);
1675 if ( toSymbol != NULL ) {
1676 if ( symbolOffset == 0 )
1677 printf(" (%s)", toSymbol);
1678 else
1679 printf(" (%s + %lld)", toSymbol, symbolOffset);
1680 }
1681 printf("\n");
1682 lastFromSymbol = s;
1683 }
1684 }
1685 }
1686 }
1687 }
1688 else {
1689 for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
1690 uint8_t kind = *p++;
1691 p = this->printSharedRegionV1InfoForEachULEB128Address(p, infoEnd, kind);
1692 }
1693 }
1694 }
1695 }
1696
1697 template <typename A>
1698 const char* DyldInfoPrinter<A>::sharedRegionKindName(uint8_t kind)
1699 {
1700 switch (kind) {
1701 default:
1702 return "<<unknown>>";
1703 case DYLD_CACHE_ADJ_V2_POINTER_32:
1704 return "pointer32";
1705 case DYLD_CACHE_ADJ_V2_POINTER_64:
1706 return "pointer64";
1707 case DYLD_CACHE_ADJ_V2_DELTA_32:
1708 return "delta32";
1709 case DYLD_CACHE_ADJ_V2_DELTA_64:
1710 return "delta64";
1711 case DYLD_CACHE_ADJ_V2_ARM64_ADRP:
1712 return "adrp";
1713 case DYLD_CACHE_ADJ_V2_ARM64_OFF12:
1714 return "off12";
1715 case DYLD_CACHE_ADJ_V2_ARM64_BR26:
1716 return "br26";
1717 case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT:
1718 return "movw/movt";
1719 case DYLD_CACHE_ADJ_V2_ARM_BR24:
1720 return "br24";
1721 case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT:
1722 return "movw/movt";
1723 case DYLD_CACHE_ADJ_V2_THUMB_BR22:
1724 return "br22";
1725 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
1726 return "off32";
1727 }
1728 }
1729
1730
1731 #if SUPPORT_ARCH_arm_any
1732 template <>
1733 void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
1734 {
1735 if ( addr & 1 )
1736 printf("0x%0llX [thumb] %s\n", (addr & -2), symbolNameForAddress(addr & -2));
1737 else
1738 printf("0x%0llX %s\n", addr, symbolNameForAddress(addr));
1739 }
1740 #endif
1741
1742 template <typename A>
1743 void DyldInfoPrinter<A>::printFunctionStartLine(uint64_t addr)
1744 {
1745 printf("0x%0llX %s\n", addr, symbolNameForAddress(addr));
1746 }
1747
1748
1749 template <typename A>
1750 void DyldInfoPrinter<A>::printFunctionStartsInfo()
1751 {
1752 if ( (fFunctionStartsInfo == NULL) || (fFunctionStartsInfo->datasize() == 0) ) {
1753 printf("no function starts info\n");
1754 }
1755 else {
1756 const uint8_t* infoStart = (uint8_t*)fHeader + fFunctionStartsInfo->dataoff();
1757 const uint8_t* infoEnd = &infoStart[fFunctionStartsInfo->datasize()];
1758 uint64_t address = fBaseAddress;
1759 for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd); ) {
1760 uint64_t delta = 0;
1761 uint32_t shift = 0;
1762 bool more = true;
1763 do {
1764 uint8_t byte = *p++;
1765 delta |= ((byte & 0x7F) << shift);
1766 shift += 7;
1767 if ( byte < 0x80 ) {
1768 address += delta;
1769 printFunctionStartLine(address);
1770 more = false;
1771 }
1772 } while (more);
1773 }
1774 }
1775 }
1776
1777 template <typename A>
1778 void DyldInfoPrinter<A>::printDylibsInfo()
1779 {
1780 printf("attributes dependent dylibs\n");
1781 for(typename std::vector<const macho_dylib_command<P>*>::iterator it = fDylibLoadCommands.begin(); it != fDylibLoadCommands.end(); ++it) {
1782 const macho_dylib_command<P>* dylib = *it;
1783 const char* attribute = "";
1784 switch ( dylib->cmd() ) {
1785 case LC_LOAD_WEAK_DYLIB:
1786 attribute = "weak_import";
1787 break;
1788 case LC_REEXPORT_DYLIB:
1789 attribute = "re-export";
1790 break;
1791 case LC_LOAD_UPWARD_DYLIB:
1792 attribute = "upward";
1793 break;
1794 case LC_LAZY_LOAD_DYLIB:
1795 attribute = "lazy_load";
1796 break;
1797 case LC_LOAD_DYLIB:
1798 default:
1799 break;
1800 }
1801 printf(" %-12s %s\n", attribute, dylib->name());
1802 }
1803 }
1804
1805 template <typename A>
1806 void DyldInfoPrinter<A>::printDRInfo()
1807 {
1808 if ( fDRInfo == NULL ) {
1809 printf("no Designated Requirements info\n");
1810 }
1811 else {
1812 printf("dylibs DRs\n");
1813 const uint8_t* start = ((uint8_t*)fHeader + fDRInfo->dataoff());
1814 //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
1815 typedef Security::SuperBlob<Security::kSecCodeMagicDRList> DRListSuperBlob;
1816 const DRListSuperBlob* topBlob = (DRListSuperBlob*)start;
1817 if ( topBlob->validateBlob(fDRInfo->datasize()) ) {
1818 if ( topBlob->count() == fDylibLoadCommands.size() ) {
1819 for(unsigned i=0; i < topBlob->count(); ++i) {
1820 printf(" %-20s ", fDylibs[i]);
1821 const Security::BlobCore* item = topBlob->find(i);
1822 if ( item != NULL ) {
1823 const uint8_t* itemStart = (uint8_t*)item;
1824 const uint8_t* itemEnd = itemStart + item->length();
1825 for(const uint8_t* p=itemStart; p < itemEnd; ++p)
1826 printf("%02X ", *p);
1827 }
1828 else {
1829 printf("no DR info");
1830 }
1831 printf("\n");
1832 }
1833 }
1834 else {
1835 fprintf(stderr, "superblob of DRs has a different number of elements than dylib load commands\n");
1836 }
1837 }
1838 else {
1839 fprintf(stderr, "superblob of DRs invalid\n");
1840 }
1841 }
1842 }
1843
1844
1845
1846
1847
1848 template <typename A>
1849 void DyldInfoPrinter<A>::printDataInCode()
1850 {
1851 if ( fDataInCode == NULL ) {
1852 printf("no data-in-code info\n");
1853 }
1854 else {
1855 printf("offset length data-kind\n");
1856 const macho_data_in_code_entry<P>* start = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff());
1857 const macho_data_in_code_entry<P>* end = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff() + fDataInCode->datasize());
1858 for (const macho_data_in_code_entry<P>* p=start; p < end; ++p) {
1859 const char* kindStr = "???";
1860 switch ( p->kind() ) {
1861 case 1:
1862 kindStr = "data";
1863 break;
1864 case 2:
1865 kindStr = "jumptable8";
1866 break;
1867 case 3:
1868 kindStr = "jumptable16";
1869 break;
1870 case 4:
1871 kindStr = "jumptable32";
1872 break;
1873 case 5:
1874 kindStr = "jumptable32absolute";
1875 break;
1876 }
1877 printf("0x%08X 0x%04X %s\n", p->offset(), p->length(), kindStr);
1878 }
1879 }
1880 }
1881
1882
1883
1884 template <>
1885 ppc::P::uint_t DyldInfoPrinter<ppc>::relocBase()
1886 {
1887 if ( fHeader->flags() & MH_SPLIT_SEGS )
1888 return fFirstWritableSegment->vmaddr();
1889 else
1890 return fFirstSegment->vmaddr();
1891 }
1892
1893 template <>
1894 ppc64::P::uint_t DyldInfoPrinter<ppc64>::relocBase()
1895 {
1896 if ( fWriteableSegmentWithAddrOver4G )
1897 return fFirstWritableSegment->vmaddr();
1898 else
1899 return fFirstSegment->vmaddr();
1900 }
1901
1902 template <>
1903 x86::P::uint_t DyldInfoPrinter<x86>::relocBase()
1904 {
1905 if ( fHeader->flags() & MH_SPLIT_SEGS )
1906 return fFirstWritableSegment->vmaddr();
1907 else
1908 return fFirstSegment->vmaddr();
1909 }
1910
1911 template <>
1912 x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
1913 {
1914 return fFirstWritableSegment->vmaddr();
1915 }
1916
1917 #if SUPPORT_ARCH_arm_any
1918 template <>
1919 arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
1920 {
1921 if ( fHeader->flags() & MH_SPLIT_SEGS )
1922 return fFirstWritableSegment->vmaddr();
1923 else
1924 return fFirstSegment->vmaddr();
1925 }
1926 #endif
1927
1928 #if SUPPORT_ARCH_arm64
1929 template <>
1930 arm64::P::uint_t DyldInfoPrinter<arm64>::relocBase()
1931 {
1932 return fFirstWritableSegment->vmaddr();
1933 }
1934 #endif
1935
1936 template <>
1937 const char* DyldInfoPrinter<ppc>::relocTypeName(uint8_t r_type)
1938 {
1939 if ( r_type == GENERIC_RELOC_VANILLA )
1940 return "pointer";
1941 else
1942 return "??";
1943 }
1944
1945 template <>
1946 const char* DyldInfoPrinter<ppc64>::relocTypeName(uint8_t r_type)
1947 {
1948 if ( r_type == GENERIC_RELOC_VANILLA )
1949 return "pointer";
1950 else
1951 return "??";
1952 }
1953
1954 template <>
1955 const char* DyldInfoPrinter<x86>::relocTypeName(uint8_t r_type)
1956 {
1957 if ( r_type == GENERIC_RELOC_VANILLA )
1958 return "pointer";
1959 else if ( r_type == GENERIC_RELOC_PB_LA_PTR )
1960 return "pb pointer";
1961 else
1962 return "??";
1963 }
1964
1965 template <>
1966 const char* DyldInfoPrinter<x86_64>::relocTypeName(uint8_t r_type)
1967 {
1968 if ( r_type == X86_64_RELOC_UNSIGNED )
1969 return "pointer";
1970 else
1971 return "??";
1972 }
1973
1974 #if SUPPORT_ARCH_arm_any
1975 template <>
1976 const char* DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
1977 {
1978 if ( r_type == ARM_RELOC_VANILLA )
1979 return "pointer";
1980 else if ( r_type == ARM_RELOC_PB_LA_PTR )
1981 return "pb pointer";
1982 else
1983 return "??";
1984 }
1985 #endif
1986
1987 #if SUPPORT_ARCH_arm64
1988 template <>
1989 const char* DyldInfoPrinter<arm64>::relocTypeName(uint8_t r_type)
1990 {
1991 if ( r_type == ARM64_RELOC_UNSIGNED )
1992 return "pointer";
1993 return "??";
1994 }
1995 #endif
1996
1997 template <typename A>
1998 void DyldInfoPrinter<A>::printRelocRebaseInfo()
1999 {
2000 if ( fDynamicSymbolTable == NULL ) {
2001 printf("no classic dynamic symbol table");
2002 }
2003 else {
2004 printf("rebase information (from local relocation records and indirect symbol table):\n");
2005 printf("segment section address type\n");
2006 // walk all local relocations
2007 pint_t rbase = relocBase();
2008 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + fDynamicSymbolTable->locreloff());
2009 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nlocrel()];
2010 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
2011 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
2012 pint_t addr = reloc->r_address() + rbase;
2013 uint8_t segIndex = segmentIndexForAddress(addr);
2014 const char* typeName = relocTypeName(reloc->r_type());
2015 const char* segName = segmentName(segIndex);
2016 const char* sectName = sectionName(segIndex, addr);
2017 printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
2018 }
2019 else {
2020 const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
2021 pint_t addr = sreloc->r_address() + rbase;
2022 uint8_t segIndex = segmentIndexForAddress(addr);
2023 const char* typeName = relocTypeName(sreloc->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);
2027 }
2028 }
2029 // look for local non-lazy-pointers
2030 const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
2031 uint8_t segIndex = 0;
2032 for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit, ++segIndex) {
2033 const macho_segment_command<P>* segCmd = *segit;
2034 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
2035 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
2036 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
2037 uint8_t type = sect->flags() & SECTION_TYPE;
2038 if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
2039 uint32_t indirectOffset = sect->reserved1();
2040 uint32_t count = sect->size() / sizeof(pint_t);
2041 for (uint32_t i=0; i < count; ++i) {
2042 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
2043 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
2044 pint_t addr = sect->addr() + i*sizeof(pint_t);
2045 const char* typeName = "pointer";
2046 const char* segName = segmentName(segIndex);
2047 const char* sectName = sectionName(segIndex, addr);
2048 printf("%-8s %-16s 0x%08llX %s\n", segName, sectName, (uint64_t)addr, typeName);
2049 }
2050 }
2051 }
2052 }
2053 }
2054 }
2055 }
2056
2057
2058 template <typename A>
2059 void DyldInfoPrinter<A>::printSymbolTableExportInfo()
2060 {
2061 if ( fDynamicSymbolTable == NULL ) {
2062 printf("no classic dynamic symbol table");
2063 }
2064 else {
2065 printf("export information (from symbol table):\n");
2066 const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
2067 for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
2068 const char* flags = "";
2069 if ( sym->n_desc() & N_WEAK_DEF )
2070 flags = "[weak_def] ";
2071 pint_t thumb = 0;
2072 if ( sym->n_desc() & N_ARM_THUMB_DEF )
2073 thumb = 1;
2074 printf("0x%08llX %s%s\n", sym->n_value()+thumb, flags, &fStrings[sym->n_strx()]);
2075 }
2076 }
2077 }
2078
2079 template <typename A>
2080 const char* DyldInfoPrinter<A>::closestSymbolNameForAddress(uint64_t addr, uint64_t* offset, uint8_t sectIndex)
2081 {
2082 const macho_nlist<P>* bestSymbol = NULL;
2083 if ( fDynamicSymbolTable != NULL ) {
2084 // find closest match in globals
2085 const macho_nlist<P>* const globalsStart = &fSymbols[fDynamicSymbolTable->iextdefsym()];
2086 const macho_nlist<P>* const globalsEnd = &globalsStart[fDynamicSymbolTable->nextdefsym()];
2087 for (const macho_nlist<P>* s = globalsStart; s < globalsEnd; ++s) {
2088 if ( (s->n_type() & N_TYPE) == N_SECT ) {
2089 if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
2090 if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
2091 bestSymbol = s;
2092 }
2093 }
2094 }
2095
2096 // find closest match in locals
2097 const macho_nlist<P>* const localsStart = &fSymbols[fDynamicSymbolTable->ilocalsym()];
2098 const macho_nlist<P>* const localsEnd = &localsStart[fDynamicSymbolTable->nlocalsym()];
2099 for (const macho_nlist<P>* s = localsStart; s < localsEnd; ++s) {
2100 if ( ((s->n_type() & N_TYPE) == N_SECT) && ((s->n_type() & N_STAB) == 0) ) {
2101 if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
2102 if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
2103 bestSymbol = s;
2104 }
2105 }
2106 }
2107 }
2108 else {
2109 // find closest match in locals
2110 const macho_nlist<P>* const allStart = &fSymbols[0];
2111 const macho_nlist<P>* const allEnd = &fSymbols[fSymbolCount];
2112 for (const macho_nlist<P>* s = allStart; s < allEnd; ++s) {
2113 if ( ((s->n_type() & N_TYPE) == N_SECT) && ((s->n_type() & N_STAB) == 0) ) {
2114 if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
2115 if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
2116 bestSymbol = s;
2117 }
2118 }
2119 }
2120 }
2121 if ( bestSymbol != NULL ) {
2122 *offset = addr - bestSymbol->n_value();
2123 return &fStrings[bestSymbol->n_strx()];
2124 }
2125 *offset = 0;
2126 return NULL;
2127 }
2128
2129 template <typename A>
2130 const char* DyldInfoPrinter<A>::symbolNameForAddress(uint64_t addr)
2131 {
2132 uint64_t offset;
2133 const char* s = closestSymbolNameForAddress(addr, &offset);
2134 if ( (offset == 0) && (s != NULL) )
2135 return s;
2136 return "?";
2137 }
2138
2139 template <typename A>
2140 void DyldInfoPrinter<A>::printClassicBindingInfo()
2141 {
2142 if ( fDynamicSymbolTable == NULL ) {
2143 printf("no classic dynamic symbol table");
2144 }
2145 else {
2146 printf("binding information (from relocations and indirect symbol table):\n");
2147 printf("segment section address type weak addend dylib symbol\n");
2148 // walk all external relocations
2149 pint_t rbase = relocBase();
2150 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + fDynamicSymbolTable->extreloff());
2151 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nextrel()];
2152 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
2153 pint_t addr = reloc->r_address() + rbase;
2154 uint32_t symbolIndex = reloc->r_symbolnum();
2155 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2156 const char* symbolName = &fStrings[sym->n_strx()];
2157 const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : "";
2158 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
2159 uint8_t segIndex = segmentIndexForAddress(addr);
2160 const char* typeName = relocTypeName(reloc->r_type());
2161 const char* segName = segmentName(segIndex);
2162 const char* sectName = sectionName(segIndex, addr);
2163 const pint_t* addressMapped = mappedAddressForVMAddress(addr);
2164 int64_t addend = P::getP(*addressMapped);
2165 if ( fHeader->flags() & MH_PREBOUND ) {
2166 // In prebound binaries the content is already pointing to the target.
2167 // To get the addend requires subtracting out the base address it was prebound to.
2168 addend -= sym->n_value();
2169 }
2170 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr,
2171 typeName, weak_import, addend, fromDylib, symbolName);
2172 }
2173 // look for non-lazy pointers
2174 const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
2175 for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) {
2176 const macho_segment_command<P>* segCmd = *segit;
2177 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
2178 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
2179 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
2180 uint8_t type = sect->flags() & SECTION_TYPE;
2181 if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
2182 uint32_t indirectOffset = sect->reserved1();
2183 uint32_t count = sect->size() / sizeof(pint_t);
2184 for (uint32_t i=0; i < count; ++i) {
2185 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
2186 if ( symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
2187 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2188 const char* symbolName = &fStrings[sym->n_strx()];
2189 const char* weak_import = (sym->n_desc() & N_WEAK_REF) ? "weak" : "";
2190 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
2191 pint_t addr = sect->addr() + i*sizeof(pint_t);
2192 uint8_t segIndex = segmentIndexForAddress(addr);
2193 const char* typeName = "pointer";
2194 const char* segName = segmentName(segIndex);
2195 const char* sectName = sectionName(segIndex, addr);
2196 int64_t addend = 0;
2197 printf("%-8s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectName, (uint64_t)addr,
2198 typeName, weak_import, addend, fromDylib, symbolName);
2199 }
2200 }
2201 }
2202 }
2203 }
2204 }
2205 }
2206
2207
2208 template <typename A>
2209 void DyldInfoPrinter<A>::printClassicLazyBindingInfo()
2210 {
2211 if ( fDynamicSymbolTable == NULL ) {
2212 printf("no classic dynamic symbol table");
2213 }
2214 else {
2215 printf("lazy binding information (from section records and indirect symbol table):\n");
2216 printf("segment section address index dylib symbol\n");
2217 const uint32_t* indirectSymbolTable = (uint32_t*)(((uint8_t*)fHeader) + fDynamicSymbolTable->indirectsymoff());
2218 for(typename std::vector<const macho_segment_command<P>*>::iterator segit=fSegments.begin(); segit != fSegments.end(); ++segit) {
2219 const macho_segment_command<P>* segCmd = *segit;
2220 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
2221 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
2222 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
2223 uint8_t type = sect->flags() & SECTION_TYPE;
2224 if ( type == S_LAZY_SYMBOL_POINTERS ) {
2225 uint32_t indirectOffset = sect->reserved1();
2226 uint32_t count = sect->size() / sizeof(pint_t);
2227 for (uint32_t i=0; i < count; ++i) {
2228 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
2229 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2230 const char* symbolName = &fStrings[sym->n_strx()];
2231 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
2232 pint_t addr = sect->addr() + i*sizeof(pint_t);
2233 uint8_t segIndex = segmentIndexForAddress(addr);
2234 const char* segName = segmentName(segIndex);
2235 const char* sectName = sectionName(segIndex, addr);
2236 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName);
2237 }
2238 }
2239 else if ( (type == S_SYMBOL_STUBS) && (((sect->flags() & S_ATTR_SELF_MODIFYING_CODE) != 0)) && (sect->reserved2() == 5) ) {
2240 // i386 self-modifying stubs
2241 uint32_t indirectOffset = sect->reserved1();
2242 uint32_t count = sect->size() / 5;
2243 for (uint32_t i=0; i < count; ++i) {
2244 uint32_t symbolIndex = E::get32(indirectSymbolTable[indirectOffset+i]);
2245 if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
2246 const macho_nlist<P>* sym = &fSymbols[symbolIndex];
2247 const char* symbolName = &fStrings[sym->n_strx()];
2248 const char* fromDylib = classicOrdinalName(GET_LIBRARY_ORDINAL(sym->n_desc()));
2249 pint_t addr = sect->addr() + i*5;
2250 uint8_t segIndex = segmentIndexForAddress(addr);
2251 const char* segName = segmentName(segIndex);
2252 const char* sectName = sectionName(segIndex, addr);
2253 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectName, (uint64_t)addr, symbolIndex, fromDylib, symbolName);
2254 }
2255 }
2256 }
2257 }
2258 }
2259 }
2260 }
2261
2262 static void dump(const char* path)
2263 {
2264 struct stat stat_buf;
2265
2266 try {
2267 int fd = ::open(path, O_RDONLY, 0);
2268 if ( fd == -1 )
2269 throw "cannot open file";
2270 if ( ::fstat(fd, &stat_buf) != 0 )
2271 throwf("fstat(%s) failed, errno=%d\n", path, errno);
2272 uint32_t length = stat_buf.st_size;
2273 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
2274 if ( p == ((uint8_t*)(-1)) )
2275 throw "cannot map file";
2276 ::close(fd);
2277 const mach_header* mh = (mach_header*)p;
2278 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
2279 const struct fat_header* fh = (struct fat_header*)p;
2280 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
2281 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
2282 size_t offset = OSSwapBigToHostInt32(archs[i].offset);
2283 size_t size = OSSwapBigToHostInt32(archs[i].size);
2284 cpu_type_t cputype = OSSwapBigToHostInt32(archs[i].cputype);
2285 cpu_type_t cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);
2286 if ( ((cputype == sPreferredArch)
2287 && ((sPreferredSubArch==0) || (sPreferredSubArch==cpusubtype)))
2288 || (sPreferredArch == 0) ) {
2289 switch(cputype) {
2290 case CPU_TYPE_POWERPC:
2291 if ( DyldInfoPrinter<ppc>::validFile(p + offset) )
2292 DyldInfoPrinter<ppc>::make(p + offset, size, path, (sPreferredArch == 0));
2293 else
2294 throw "in universal file, ppc slice does not contain ppc mach-o";
2295 break;
2296 case CPU_TYPE_I386:
2297 if ( DyldInfoPrinter<x86>::validFile(p + offset) )
2298 DyldInfoPrinter<x86>::make(p + offset, size, path, (sPreferredArch == 0));
2299 else
2300 throw "in universal file, i386 slice does not contain i386 mach-o";
2301 break;
2302 case CPU_TYPE_POWERPC64:
2303 if ( DyldInfoPrinter<ppc64>::validFile(p + offset) )
2304 DyldInfoPrinter<ppc64>::make(p + offset, size, path, (sPreferredArch == 0));
2305 else
2306 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
2307 break;
2308 case CPU_TYPE_X86_64:
2309 if ( DyldInfoPrinter<x86_64>::validFile(p + offset) )
2310 DyldInfoPrinter<x86_64>::make(p + offset, size, path, (sPreferredArch == 0));
2311 else
2312 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
2313 break;
2314 #if SUPPORT_ARCH_arm_any
2315 case CPU_TYPE_ARM:
2316 if ( DyldInfoPrinter<arm>::validFile(p + offset) )
2317 DyldInfoPrinter<arm>::make(p + offset, size, path, (sPreferredArch == 0));
2318 else
2319 throw "in universal file, arm slice does not contain arm mach-o";
2320 break;
2321 #endif
2322 #if SUPPORT_ARCH_arm64
2323 case CPU_TYPE_ARM64:
2324 if ( DyldInfoPrinter<arm64>::validFile(p + offset) )
2325 DyldInfoPrinter<arm64>::make(p + offset, size, path, (sPreferredArch == 0));
2326 else
2327 throw "in universal file, arm64 slice does not contain arm mach-o";
2328 break;
2329 #endif
2330 default:
2331 throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
2332 }
2333 }
2334 }
2335 }
2336 else if ( DyldInfoPrinter<x86>::validFile(p) ) {
2337 DyldInfoPrinter<x86>::make(p, length, path, false);
2338 }
2339 else if ( DyldInfoPrinter<ppc>::validFile(p) ) {
2340 DyldInfoPrinter<ppc>::make(p, length, path, false);
2341 }
2342 else if ( DyldInfoPrinter<ppc64>::validFile(p) ) {
2343 DyldInfoPrinter<ppc64>::make(p, length, path, false);
2344 }
2345 else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
2346 DyldInfoPrinter<x86_64>::make(p, length, path, false);
2347 }
2348 #if SUPPORT_ARCH_arm_any
2349 else if ( DyldInfoPrinter<arm>::validFile(p) ) {
2350 DyldInfoPrinter<arm>::make(p, length, path, false);
2351 }
2352 #endif
2353 #if SUPPORT_ARCH_arm64
2354 else if ( DyldInfoPrinter<arm64>::validFile(p) ) {
2355 DyldInfoPrinter<arm64>::make(p, length, path, false);
2356 }
2357 #endif
2358 else {
2359 throw "not a known file type";
2360 }
2361 }
2362 catch (const char* msg) {
2363 throwf("%s in %s", msg, path);
2364 }
2365 }
2366
2367 static void usage()
2368 {
2369 fprintf(stderr, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
2370 "\t-dylibs print dependent dylibs\n"
2371 "\t-dr print dependent dylibs and show any recorded DR info\n"
2372 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
2373 "\t-bind print addresses dyld will set based on symbolic lookups\n"
2374 "\t-weak_bind print symbols which dyld must coalesce\n"
2375 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
2376 "\t-export print addresses of all symbols this file exports\n"
2377 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
2378 "\t-function_starts print table of function start addresses\n"
2379 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
2380 "\t-data_in_code print any data-in-code information\n"
2381 );
2382 }
2383
2384
2385 int main(int argc, const char* argv[])
2386 {
2387 if ( argc == 1 ) {
2388 usage();
2389 return 0;
2390 }
2391
2392 try {
2393 std::vector<const char*> files;
2394 for(int i=1; i < argc; ++i) {
2395 const char* arg = argv[i];
2396 if ( arg[0] == '-' ) {
2397 if ( strcmp(arg, "-arch") == 0 ) {
2398 const char* arch = ++i<argc? argv[i]: "";
2399 if ( strcmp(arch, "ppc64") == 0 )
2400 sPreferredArch = CPU_TYPE_POWERPC64;
2401 else if ( strcmp(arch, "ppc") == 0 )
2402 sPreferredArch = CPU_TYPE_POWERPC;
2403 else if ( strcmp(arch, "i386") == 0 )
2404 sPreferredArch = CPU_TYPE_I386;
2405 else if ( strcmp(arch, "x86_64") == 0 )
2406 sPreferredArch = CPU_TYPE_X86_64;
2407 #if SUPPORT_ARCH_arm64
2408 else if ( strcmp(arch, "arm64") == 0 )
2409 sPreferredArch = CPU_TYPE_ARM64;
2410 #endif
2411 else {
2412 if ( arch == NULL )
2413 throw "-arch missing architecture name";
2414 bool found = false;
2415 for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
2416 if ( strcmp(t->archName,arch) == 0 ) {
2417 sPreferredArch = t->cpuType;
2418 if ( t->isSubType )
2419 sPreferredSubArch = t->cpuSubType;
2420 found = true;
2421 break;
2422 }
2423 }
2424 if ( !found )
2425 throwf("unknown architecture %s", arch);
2426 }
2427 }
2428 else if ( strcmp(arg, "-rebase") == 0 ) {
2429 printRebase = true;
2430 }
2431 else if ( strcmp(arg, "-bind") == 0 ) {
2432 printBind = true;
2433 }
2434 else if ( strcmp(arg, "-weak_bind") == 0 ) {
2435 printWeakBind = true;
2436 }
2437 else if ( strcmp(arg, "-lazy_bind") == 0 ) {
2438 printLazyBind = true;
2439 }
2440 else if ( strcmp(arg, "-export") == 0 ) {
2441 printExport = true;
2442 }
2443 else if ( strcmp(arg, "-opcodes") == 0 ) {
2444 printOpcodes = true;
2445 }
2446 else if ( strcmp(arg, "-export_dot") == 0 ) {
2447 printExportGraph = true;
2448 }
2449 else if ( strcmp(arg, "-export_trie_nodes") == 0 ) {
2450 printExportNodes = true;
2451 }
2452 else if ( strcmp(arg, "-shared_region") == 0 ) {
2453 printSharedRegion = true;
2454 }
2455 else if ( strcmp(arg, "-function_starts") == 0 ) {
2456 printFunctionStarts = true;
2457 }
2458 else if ( strcmp(arg, "-dylibs") == 0 ) {
2459 printDylibs = true;
2460 }
2461 else if ( strcmp(arg, "-dr") == 0 ) {
2462 printDRs = true;
2463 }
2464 else if ( strcmp(arg, "-data_in_code") == 0 ) {
2465 printDataCode = true;
2466 }
2467 else {
2468 throwf("unknown option: %s\n", arg);
2469 }
2470 }
2471 else {
2472 files.push_back(arg);
2473 }
2474 }
2475 if ( files.size() == 0 )
2476 usage();
2477 if ( files.size() == 1 ) {
2478 dump(files[0]);
2479 }
2480 else {
2481 for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
2482 printf("\n%s:\n", *it);
2483 dump(*it);
2484 }
2485 }
2486 }
2487 catch (const char* msg) {
2488 fprintf(stderr, "dyldinfo failed: %s\n", msg);
2489 return 1;
2490 }
2491
2492 return 0;
2493 }
2494
2495
2496