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