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