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