]> git.saurik.com Git - apple/ld64.git/blob - src/other/dyldinfo.cpp
4af50ffde46c07e1c1df11f5cb2e36d020132523
[apple/ld64.git] / src / other / dyldinfo.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008 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
42 static bool printRebase = false;
43 static bool printBind = false;
44 static bool printWeakBind = false;
45 static bool printLazyBind = false;
46 static bool printOpcodes = false;
47 static bool printExport = false;
48 static bool printExportGraph = false;
49 static cpu_type_t sPreferredArch = CPU_TYPE_I386;
50
51
52 __attribute__((noreturn))
53 void throwf(const char* format, ...)
54 {
55 va_list list;
56 char* p;
57 va_start(list, format);
58 vasprintf(&p, format, list);
59 va_end(list);
60
61 const char* t = p;
62 throw t;
63 }
64
65
66 template <typename A>
67 class DyldInfoPrinter
68 {
69 public:
70 static bool validFile(const uint8_t* fileContent);
71 static DyldInfoPrinter<A>* make(const uint8_t* fileContent, uint32_t fileLength, const char* path)
72 { return new DyldInfoPrinter<A>(fileContent, fileLength, path); }
73 virtual ~DyldInfoPrinter() {}
74
75
76 private:
77 typedef typename A::P P;
78 typedef typename A::P::E E;
79 typedef typename A::P::uint_t pint_t;
80
81 class CStringEquals
82 {
83 public:
84 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
85 };
86
87 typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringSet;
88
89 DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path);
90 void printRebaseInfo();
91 void printRebaseInfoOpcodes();
92 void printBindingInfo();
93 void printWeakBindingInfo();
94 void printLazyBindingInfo();
95 void printBindingInfoOpcodes(bool weakBinding);
96 void printWeakBindingInfoOpcodes();
97 void printLazyBindingOpcodes();
98 void printExportInfo();
99 void printExportInfoGraph();
100 void processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end,
101 char* cummulativeString, int curStrOffset);
102 void processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
103 const uint8_t* parent, const uint8_t* p,
104 char* cummulativeString, int curStrOffset);
105 const char* rebaseTypeName(uint8_t type);
106 const char* bindTypeName(uint8_t type);
107 pint_t segStartAddress(uint8_t segIndex);
108 const char* segmentName(uint8_t segIndex);
109 const char* sectionName(uint8_t segIndex, pint_t address);
110 const char* getSegAndSectName(uint8_t segIndex, pint_t address);
111 const char* ordinalName(int libraryOrdinal);
112
113
114 const char* fPath;
115 const macho_header<P>* fHeader;
116 uint64_t fLength;
117 const char* fStrings;
118 const char* fStringsEnd;
119 const macho_nlist<P>* fSymbols;
120 uint32_t fSymbolCount;
121 const macho_dyld_info_command<P>* fInfo;
122 uint64_t fBaseAddress;
123 std::vector<const macho_segment_command<P>*>fSegments;
124 std::vector<const char*> fDylibs;
125 };
126
127
128
129 template <>
130 bool DyldInfoPrinter<ppc>::validFile(const uint8_t* fileContent)
131 {
132 const macho_header<P>* header = (const macho_header<P>*)fileContent;
133 if ( header->magic() != MH_MAGIC )
134 return false;
135 if ( header->cputype() != CPU_TYPE_POWERPC )
136 return false;
137 switch (header->filetype()) {
138 case MH_EXECUTE:
139 case MH_DYLIB:
140 case MH_BUNDLE:
141 case MH_DYLINKER:
142 return true;
143 }
144 return false;
145 }
146
147 template <>
148 bool DyldInfoPrinter<ppc64>::validFile(const uint8_t* fileContent)
149 {
150 const macho_header<P>* header = (const macho_header<P>*)fileContent;
151 if ( header->magic() != MH_MAGIC_64 )
152 return false;
153 if ( header->cputype() != CPU_TYPE_POWERPC64 )
154 return false;
155 switch (header->filetype()) {
156 case MH_EXECUTE:
157 case MH_DYLIB:
158 case MH_BUNDLE:
159 case MH_DYLINKER:
160 return true;
161 }
162 return false;
163 }
164
165 template <>
166 bool DyldInfoPrinter<x86>::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_I386 )
172 return false;
173 switch (header->filetype()) {
174 case MH_EXECUTE:
175 case MH_DYLIB:
176 case MH_BUNDLE:
177 case MH_DYLINKER:
178 return true;
179 }
180 return false;
181 }
182
183 template <>
184 bool DyldInfoPrinter<x86_64>::validFile(const uint8_t* fileContent)
185 {
186 const macho_header<P>* header = (const macho_header<P>*)fileContent;
187 if ( header->magic() != MH_MAGIC_64 )
188 return false;
189 if ( header->cputype() != CPU_TYPE_X86_64 )
190 return false;
191 switch (header->filetype()) {
192 case MH_EXECUTE:
193 case MH_DYLIB:
194 case MH_BUNDLE:
195 case MH_DYLINKER:
196 return true;
197 }
198 return false;
199 }
200
201 template <>
202 bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
203 {
204 const macho_header<P>* header = (const macho_header<P>*)fileContent;
205 if ( header->magic() != MH_MAGIC )
206 return false;
207 if ( header->cputype() != CPU_TYPE_ARM )
208 return false;
209 switch (header->filetype()) {
210 case MH_EXECUTE:
211 case MH_DYLIB:
212 case MH_BUNDLE:
213 case MH_DYLINKER:
214 return true;
215 }
216 return false;
217 }
218
219
220 template <typename A>
221 DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path)
222 : fHeader(NULL), fLength(fileLength),
223 fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL), fBaseAddress(0)
224 {
225 // sanity check
226 if ( ! validFile(fileContent) )
227 throw "not a mach-o file that can be checked";
228
229 fPath = strdup(path);
230 fHeader = (const macho_header<P>*)fileContent;
231
232 // get LC_DYLD_INFO
233 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
234 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
235 const uint32_t cmd_count = fHeader->ncmds();
236 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
237 const macho_load_command<P>* cmd = cmds;
238 for (uint32_t i = 0; i < cmd_count; ++i) {
239 uint32_t size = cmd->cmdsize();
240 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
241 if ( endOfCmd > endOfLoadCommands )
242 throwf("load command #%d extends beyond the end of the load commands", i);
243 if ( endOfCmd > endOfFile )
244 throwf("load command #%d extends beyond the end of the file", i);
245 switch ( cmd->cmd() ) {
246 case LC_DYLD_INFO:
247 case LC_DYLD_INFO_ONLY:
248 fInfo = (macho_dyld_info_command<P>*)cmd;
249 break;
250 case macho_segment_command<P>::CMD:
251 {
252 const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
253 fSegments.push_back(segCmd);
254 if ( (segCmd->fileoff() == 0) && (segCmd->filesize() != 0) )
255 fBaseAddress = segCmd->vmaddr();
256 }
257 break;
258 case LC_LOAD_DYLIB:
259 case LC_LOAD_WEAK_DYLIB:
260 case LC_REEXPORT_DYLIB:
261 case LC_LAZY_LOAD_DYLIB:
262 {
263 const macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
264 const char* lastSlash = strrchr(dylib->name(), '/');
265 const char* leafName = (lastSlash != NULL) ? lastSlash+1 : dylib->name();
266 const char* firstDot = strchr(leafName, '.');
267 if ( firstDot != NULL ) {
268 char* t = strdup(leafName);
269 t[firstDot-leafName] = '\0';
270 fDylibs.push_back(t);
271 }
272 else {
273 fDylibs.push_back(leafName);
274 }
275 }
276 break;
277 }
278 cmd = (const macho_load_command<P>*)endOfCmd;
279 }
280
281 if ( printRebase )
282 printRebaseInfo();
283 if ( printBind )
284 printBindingInfo();
285 if ( printWeakBind )
286 printWeakBindingInfo();
287 if ( printLazyBind )
288 printLazyBindingInfo();
289 if ( printExport )
290 printExportInfo();
291 if ( printOpcodes ) {
292 printRebaseInfoOpcodes();
293 printBindingInfoOpcodes(false);
294 printBindingInfoOpcodes(true);
295 printLazyBindingOpcodes();
296 }
297 if ( printExportGraph )
298 printExportInfoGraph();
299 }
300
301 static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
302 {
303 uint64_t result = 0;
304 int bit = 0;
305 do {
306 if (p == end)
307 throwf("malformed uleb128");
308
309 uint64_t slice = *p & 0x7f;
310
311 if (bit >= 64 || slice << bit >> bit != slice)
312 throwf("uleb128 too big");
313 else {
314 result |= (slice << bit);
315 bit += 7;
316 }
317 }
318 while (*p++ & 0x80);
319 return result;
320 }
321
322 static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
323 {
324 int64_t result = 0;
325 int bit = 0;
326 uint8_t byte;
327 do {
328 if (p == end)
329 throwf("malformed sleb128");
330 byte = *p++;
331 result |= ((byte & 0x7f) << bit);
332 bit += 7;
333 } while (byte & 0x80);
334 // sign extend negative numbers
335 if ( (byte & 0x40) != 0 )
336 result |= (-1LL) << bit;
337 return result;
338 }
339
340
341 template <typename A>
342 const char* DyldInfoPrinter<A>::rebaseTypeName(uint8_t type)
343 {
344 switch (type ){
345 case REBASE_TYPE_POINTER:
346 return "pointer";
347 case REBASE_TYPE_TEXT_ABSOLUTE32:
348 return "text abs32";
349 case REBASE_TYPE_TEXT_PCREL32:
350 return "text rel32";
351 }
352 return "!!unknown!!";
353 }
354
355
356 template <typename A>
357 const char* DyldInfoPrinter<A>::bindTypeName(uint8_t type)
358 {
359 switch (type ){
360 case BIND_TYPE_POINTER:
361 return "pointer";
362 case BIND_TYPE_TEXT_ABSOLUTE32:
363 return "text abs32";
364 case BIND_TYPE_TEXT_PCREL32:
365 return "text rel32";
366 }
367 return "!!unknown!!";
368 }
369
370
371 template <typename A>
372 typename A::P::uint_t DyldInfoPrinter<A>::segStartAddress(uint8_t segIndex)
373 {
374 if ( segIndex > fSegments.size() )
375 throw "segment index out of range";
376 return fSegments[segIndex]->vmaddr();
377 }
378
379 template <typename A>
380 const char* DyldInfoPrinter<A>::segmentName(uint8_t segIndex)
381 {
382 if ( segIndex > fSegments.size() )
383 throw "segment index out of range";
384 return fSegments[segIndex]->segname();
385 }
386
387 template <typename A>
388 const char* DyldInfoPrinter<A>::sectionName(uint8_t segIndex, pint_t address)
389 {
390 if ( segIndex > fSegments.size() )
391 throw "segment index out of range";
392 const macho_segment_command<P>* segCmd = fSegments[segIndex];
393 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
394 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
395 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
396 if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
397 if ( strlen(sect->sectname()) > 15 ) {
398 static char temp[18];
399 strlcpy(temp, sect->sectname(), 17);
400 return temp;
401 }
402 else {
403 return sect->sectname();
404 }
405 }
406 }
407 return "??";
408 }
409
410 template <typename A>
411 const char* DyldInfoPrinter<A>::getSegAndSectName(uint8_t segIndex, pint_t address)
412 {
413 static char buffer[64];
414 strcpy(buffer, segmentName(segIndex));
415 strcat(buffer, "/");
416 const macho_segment_command<P>* segCmd = fSegments[segIndex];
417 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
418 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
419 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
420 if ( (sect->addr() <= address) && (address < (sect->addr()+sect->size())) ) {
421 // section name may not be zero terminated
422 char* end = &buffer[strlen(buffer)];
423 strlcpy(end, sect->sectname(), 16);
424 return buffer;
425 }
426 }
427 return "??";
428 }
429
430 template <typename A>
431 const char* DyldInfoPrinter<A>::ordinalName(int libraryOrdinal)
432 {
433 switch ( libraryOrdinal) {
434 case BIND_SPECIAL_DYLIB_SELF:
435 return "this-image";
436 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
437 return "main-executable";
438 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
439 return "flat-namespace";
440 }
441 if ( libraryOrdinal < BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
442 throw "unknown special ordinal";
443 if ( libraryOrdinal > fDylibs.size() )
444 throw "libraryOrdinal out of range";
445 return fDylibs[libraryOrdinal-1];
446 }
447
448
449 template <typename A>
450 void DyldInfoPrinter<A>::printRebaseInfo()
451 {
452 if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
453 printf("no compressed rebase info\n");
454 }
455 else {
456 printf("rebase information:\n");
457 printf("segment section address type\n");
458
459 const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
460 const uint8_t* end = &p[fInfo->rebase_size()];
461
462 uint8_t type = 0;
463 uint64_t segOffset = 0;
464 uint32_t count;
465 uint32_t skip;
466 int segIndex;
467 pint_t segStartAddr = 0;
468 const char* segName = "??";
469 const char* typeName = "??";
470 bool done = false;
471 while ( !done && (p < end) ) {
472 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
473 uint8_t opcode = *p & REBASE_OPCODE_MASK;
474 ++p;
475 switch (opcode) {
476 case REBASE_OPCODE_DONE:
477 done = true;
478 break;
479 case REBASE_OPCODE_SET_TYPE_IMM:
480 type = immediate;
481 typeName = rebaseTypeName(type);
482 break;
483 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
484 segIndex = immediate;
485 segStartAddr = segStartAddress(segIndex);
486 segName = segmentName(segIndex);
487 segOffset = read_uleb128(p, end);
488 break;
489 case REBASE_OPCODE_ADD_ADDR_ULEB:
490 segOffset += read_uleb128(p, end);
491 break;
492 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
493 segOffset += immediate*sizeof(pint_t);
494 break;
495 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
496 for (int i=0; i < immediate; ++i) {
497 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
498 segOffset += sizeof(pint_t);
499 }
500 break;
501 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
502 count = read_uleb128(p, end);
503 for (uint32_t i=0; i < count; ++i) {
504 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
505 segOffset += sizeof(pint_t);
506 }
507 break;
508 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
509 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
510 segOffset += read_uleb128(p, end) + sizeof(pint_t);
511 break;
512 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
513 count = read_uleb128(p, end);
514 skip = read_uleb128(p, end);
515 for (uint32_t i=0; i < count; ++i) {
516 printf("%-7s %-16s 0x%08llX %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
517 segOffset += skip + sizeof(pint_t);
518 }
519 break;
520 default:
521 throwf("bad rebase opcode %d", *p);
522 }
523 }
524 }
525
526 }
527
528
529
530 template <typename A>
531 void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
532 {
533 if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
534 printf("no compressed rebase info\n");
535 }
536 else {
537 printf("rebase opcodes:\n");
538 const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
539 const uint8_t* end = &p[fInfo->rebase_size()];
540
541 uint8_t type = 0;
542 uint64_t address = fBaseAddress;
543 uint32_t count;
544 uint32_t skip;
545 unsigned int segmentIndex;
546 bool done = false;
547 while ( !done && (p < end) ) {
548 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
549 uint8_t opcode = *p & REBASE_OPCODE_MASK;
550 ++p;
551 switch (opcode) {
552 case REBASE_OPCODE_DONE:
553 done = true;
554 printf("REBASE_OPCODE_DONE()\n");
555 break;
556 case REBASE_OPCODE_SET_TYPE_IMM:
557 type = immediate;
558 printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type);
559 break;
560 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
561 segmentIndex = immediate;
562 address = read_uleb128(p, end);
563 printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex, address);
564 break;
565 case REBASE_OPCODE_ADD_ADDR_ULEB:
566 address = read_uleb128(p, end);
567 printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address);
568 break;
569 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
570 address = immediate*sizeof(pint_t);
571 printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address);
572 break;
573 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
574 printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate);
575 break;
576 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
577 count = read_uleb128(p, end);
578 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count);
579 break;
580 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
581 skip = read_uleb128(p, end) + sizeof(pint_t);
582 printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip);
583 break;
584 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
585 count = read_uleb128(p, end);
586 skip = read_uleb128(p, end);
587 printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count, skip);
588 break;
589 default:
590 throwf("bad rebase opcode %d", *p);
591 }
592 }
593 }
594
595 }
596
597
598
599
600
601
602 template <typename A>
603 void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
604 {
605 if ( fInfo == NULL ) {
606 printf("no compressed binding info\n");
607 }
608 else if ( !weakbinding && (fInfo->bind_off() == 0) ) {
609 printf("no compressed binding info\n");
610 }
611 else if ( weakbinding && (fInfo->weak_bind_off() == 0) ) {
612 printf("no compressed weak binding info\n");
613 }
614 else {
615 const uint8_t* start;
616 const uint8_t* end;
617 if ( weakbinding ) {
618 printf("weak binding opcodes:\n");
619 start = (uint8_t*)fHeader + fInfo->weak_bind_off();
620 end = &start[fInfo->weak_bind_size()];
621 }
622 else {
623 printf("binding opcodes:\n");
624 start = (uint8_t*)fHeader + fInfo->bind_off();
625 end = &start[fInfo->bind_size()];
626 }
627 const uint8_t* p = start;
628 uint8_t type = 0;
629 uint8_t flags;
630 uint64_t address = fBaseAddress;
631 const char* symbolName = NULL;
632 int libraryOrdinal = 0;
633 int64_t addend = 0;
634 uint32_t segmentIndex = 0;
635 uint32_t count;
636 uint32_t skip;
637 bool done = false;
638 while ( !done && (p < end) ) {
639 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
640 uint8_t opcode = *p & BIND_OPCODE_MASK;
641 uint32_t opcodeOffset = p-start;
642 ++p;
643 switch (opcode) {
644 case BIND_OPCODE_DONE:
645 done = true;
646 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
647 break;
648 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
649 libraryOrdinal = immediate;
650 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
651 break;
652 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
653 libraryOrdinal = read_uleb128(p, end);
654 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
655 break;
656 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
657 // the special ordinals are negative numbers
658 if ( immediate == 0 )
659 libraryOrdinal = 0;
660 else {
661 int8_t signExtended = BIND_OPCODE_MASK | immediate;
662 libraryOrdinal = signExtended;
663 }
664 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
665 break;
666 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
667 flags = immediate;
668 symbolName = (char*)p;
669 while (*p != '\0')
670 ++p;
671 ++p;
672 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
673 break;
674 case BIND_OPCODE_SET_TYPE_IMM:
675 type = immediate;
676 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
677 break;
678 case BIND_OPCODE_SET_ADDEND_SLEB:
679 addend = read_sleb128(p, end);
680 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
681 break;
682 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
683 segmentIndex = immediate;
684 address = read_uleb128(p, end);
685 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
686 break;
687 case BIND_OPCODE_ADD_ADDR_ULEB:
688 skip = read_uleb128(p, end);
689 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
690 break;
691 case BIND_OPCODE_DO_BIND:
692 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
693 break;
694 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
695 skip = read_uleb128(p, end);
696 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
697 break;
698 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
699 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
700 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
701 break;
702 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
703 count = read_uleb128(p, end);
704 skip = read_uleb128(p, end);
705 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
706 break;
707 default:
708 throwf("unknown bind opcode %d", *p);
709 }
710 }
711 }
712
713 }
714
715
716
717 template <typename A>
718 void DyldInfoPrinter<A>::printBindingInfo()
719 {
720 if ( (fInfo == NULL) || (fInfo->bind_off() == 0) ) {
721 printf("no compressed binding info\n");
722 }
723 else {
724 printf("bind information:\n");
725 printf("segment section address type addend dylib symbol\n");
726 const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
727 const uint8_t* end = &p[fInfo->bind_size()];
728
729 uint8_t type = 0;
730 uint8_t segIndex = 0;
731 uint64_t segOffset = 0;
732 const char* symbolName = NULL;
733 const char* fromDylib = "??";
734 int libraryOrdinal = 0;
735 int64_t addend = 0;
736 uint32_t count;
737 uint32_t skip;
738 pint_t segStartAddr = 0;
739 const char* segName = "??";
740 const char* typeName = "??";
741 bool done = false;
742 while ( !done && (p < end) ) {
743 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
744 uint8_t opcode = *p & BIND_OPCODE_MASK;
745 ++p;
746 switch (opcode) {
747 case BIND_OPCODE_DONE:
748 done = true;
749 break;
750 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
751 libraryOrdinal = immediate;
752 fromDylib = ordinalName(libraryOrdinal);
753 break;
754 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
755 libraryOrdinal = read_uleb128(p, end);
756 fromDylib = ordinalName(libraryOrdinal);
757 break;
758 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
759 // the special ordinals are negative numbers
760 if ( immediate == 0 )
761 libraryOrdinal = 0;
762 else {
763 int8_t signExtended = BIND_OPCODE_MASK | immediate;
764 libraryOrdinal = signExtended;
765 }
766 fromDylib = ordinalName(libraryOrdinal);
767 break;
768 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
769 symbolName = (char*)p;
770 while (*p != '\0')
771 ++p;
772 ++p;
773 break;
774 case BIND_OPCODE_SET_TYPE_IMM:
775 type = immediate;
776 typeName = bindTypeName(type);
777 break;
778 case BIND_OPCODE_SET_ADDEND_SLEB:
779 addend = read_sleb128(p, end);
780 break;
781 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
782 segIndex = immediate;
783 segStartAddr = segStartAddress(segIndex);
784 segName = segmentName(segIndex);
785 segOffset = read_uleb128(p, end);
786 break;
787 case BIND_OPCODE_ADD_ADDR_ULEB:
788 segOffset += read_uleb128(p, end);
789 break;
790 case BIND_OPCODE_DO_BIND:
791 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName );
792 segOffset += sizeof(pint_t);
793 break;
794 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
795 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName );
796 segOffset += read_uleb128(p, end) + sizeof(pint_t);
797 break;
798 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
799 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName );
800 segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
801 break;
802 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
803 count = read_uleb128(p, end);
804 skip = read_uleb128(p, end);
805 for (uint32_t i=0; i < count; ++i) {
806 printf("%-7s %-16s 0x%08llX %10s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName );
807 segOffset += skip + sizeof(pint_t);
808 }
809 break;
810 default:
811 throwf("bad bind opcode %d", *p);
812 }
813 }
814 }
815
816 }
817
818 template <typename A>
819 void DyldInfoPrinter<A>::printWeakBindingInfo()
820 {
821 if ( (fInfo == NULL) || (fInfo->weak_bind_off() == 0) ) {
822 printf("no weak binding\n");
823 }
824 else {
825 printf("weak binding information:\n");
826 printf("segment section address type addend symbol\n");
827 const uint8_t* p = (uint8_t*)fHeader + fInfo->weak_bind_off();
828 const uint8_t* end = &p[fInfo->weak_bind_size()];
829
830 uint8_t type = 0;
831 uint8_t segIndex = 0;
832 uint64_t segOffset = 0;
833 const char* symbolName = NULL;
834 int64_t addend = 0;
835 uint32_t count;
836 uint32_t skip;
837 pint_t segStartAddr = 0;
838 const char* segName = "??";
839 const char* typeName = "??";
840 bool done = false;
841 while ( !done && (p < end) ) {
842 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
843 uint8_t opcode = *p & BIND_OPCODE_MASK;
844 ++p;
845 switch (opcode) {
846 case BIND_OPCODE_DONE:
847 done = true;
848 break;
849 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
850 symbolName = (char*)p;
851 while (*p != '\0')
852 ++p;
853 ++p;
854 if ( (immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) != 0 )
855 printf(" strong %s\n", symbolName );
856 break;
857 case BIND_OPCODE_SET_TYPE_IMM:
858 type = immediate;
859 typeName = bindTypeName(type);
860 break;
861 case BIND_OPCODE_SET_ADDEND_SLEB:
862 addend = read_sleb128(p, end);
863 break;
864 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
865 segIndex = immediate;
866 segStartAddr = segStartAddress(segIndex);
867 segName = segmentName(segIndex);
868 segOffset = read_uleb128(p, end);
869 break;
870 case BIND_OPCODE_ADD_ADDR_ULEB:
871 segOffset += read_uleb128(p, end);
872 break;
873 case BIND_OPCODE_DO_BIND:
874 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
875 segOffset += sizeof(pint_t);
876 break;
877 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
878 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
879 segOffset += read_uleb128(p, end) + sizeof(pint_t);
880 break;
881 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
882 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
883 segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
884 break;
885 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
886 count = read_uleb128(p, end);
887 skip = read_uleb128(p, end);
888 for (uint32_t i=0; i < count; ++i) {
889 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
890 segOffset += skip + sizeof(pint_t);
891 }
892 break;
893 default:
894 throwf("unknown weak bind opcode %d", *p);
895 }
896 }
897 }
898
899 }
900
901
902 template <typename A>
903 void DyldInfoPrinter<A>::printLazyBindingInfo()
904 {
905 if ( fInfo == NULL ) {
906 printf("no compressed dyld info\n");
907 }
908 else if ( fInfo->lazy_bind_off() == 0 ) {
909 printf("no compressed lazy binding info\n");
910 }
911 else {
912 printf("lazy binding information:\n");
913 printf("segment section address index dylib symbol\n");
914 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
915 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
916
917 uint8_t type = BIND_TYPE_POINTER;
918 uint8_t segIndex = 0;
919 uint64_t segOffset = 0;
920 const char* symbolName = NULL;
921 const char* fromDylib = "??";
922 int libraryOrdinal = 0;
923 int64_t addend = 0;
924 uint32_t lazy_offset = 0;
925 pint_t segStartAddr = 0;
926 const char* segName = "??";
927 const char* typeName = "??";
928 for (const uint8_t* p=start; p < end; ) {
929 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
930 uint8_t opcode = *p & BIND_OPCODE_MASK;
931 ++p;
932 switch (opcode) {
933 case BIND_OPCODE_DONE:
934 lazy_offset = p-start;
935 break;
936 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
937 libraryOrdinal = immediate;
938 fromDylib = ordinalName(libraryOrdinal);
939 break;
940 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
941 libraryOrdinal = read_uleb128(p, end);
942 fromDylib = ordinalName(libraryOrdinal);
943 break;
944 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
945 // the special ordinals are negative numbers
946 if ( immediate == 0 )
947 libraryOrdinal = 0;
948 else {
949 int8_t signExtended = BIND_OPCODE_MASK | immediate;
950 libraryOrdinal = signExtended;
951 }
952 fromDylib = ordinalName(libraryOrdinal);
953 break;
954 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
955 symbolName = (char*)p;
956 while (*p != '\0')
957 ++p;
958 ++p;
959 break;
960 case BIND_OPCODE_SET_TYPE_IMM:
961 type = immediate;
962 typeName = bindTypeName(type);
963 break;
964 case BIND_OPCODE_SET_ADDEND_SLEB:
965 addend = read_sleb128(p, end);
966 break;
967 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
968 segIndex = immediate;
969 segStartAddr = segStartAddress(segIndex);
970 segName = segmentName(segIndex);
971 segOffset = read_uleb128(p, end);
972 break;
973 case BIND_OPCODE_ADD_ADDR_ULEB:
974 segOffset += read_uleb128(p, end);
975 break;
976 case BIND_OPCODE_DO_BIND:
977 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName );
978 segOffset += sizeof(pint_t);
979 break;
980 default:
981 throwf("bad lazy bind opcode %d", *p);
982 }
983 }
984 }
985
986 }
987
988 #if 0
989 uint8_t type = BIND_TYPE_POINTER;
990 uint8_t flags;
991 uint64_t address = fBaseAddress;
992 const char* symbolName = NULL;
993 int libraryOrdinal = 0;
994 int64_t addend = 0;
995 uint32_t segmentIndex = 0;
996 uint32_t count;
997 uint32_t skip;
998 for (const uint8_t* p = start; p < end; ) {
999 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1000 uint8_t opcode = *p & BIND_OPCODE_MASK;
1001 uint32_t opcodeOffset = p-start;
1002 ++p;
1003 switch (opcode) {
1004 case BIND_OPCODE_DONE:
1005 printf("0x%08X BIND_OPCODE_DONE\n", opcodeOffset);
1006 break;
1007 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1008 libraryOrdinal = immediate;
1009 printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1010 break;
1011 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1012 libraryOrdinal = read_uleb128(p, end);
1013 printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
1014 break;
1015 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1016 // the special ordinals are negative numbers
1017 if ( immediate == 0 )
1018 libraryOrdinal = 0;
1019 else {
1020 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1021 libraryOrdinal = signExtended;
1022 }
1023 printf("0x%08X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1024 break;
1025 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1026 flags = immediate;
1027 symbolName = (char*)p;
1028 while (*p != '\0')
1029 ++p;
1030 ++p;
1031 printf("0x%08X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
1032 break;
1033 case BIND_OPCODE_SET_TYPE_IMM:
1034 type = immediate;
1035 printf("0x%08X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
1036 break;
1037 case BIND_OPCODE_SET_ADDEND_SLEB:
1038 addend = read_sleb128(p, end);
1039 printf("0x%08X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
1040 break;
1041 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1042 segmentIndex = immediate;
1043 address = read_uleb128(p, end);
1044 printf("0x%08X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
1045 break;
1046 case BIND_OPCODE_ADD_ADDR_ULEB:
1047 skip = read_uleb128(p, end);
1048 printf("0x%08X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1049 break;
1050 case BIND_OPCODE_DO_BIND:
1051 printf("0x%08X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
1052 break;
1053 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1054 skip = read_uleb128(p, end);
1055 printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1056 break;
1057 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1058 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
1059 printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
1060 break;
1061 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1062 count = read_uleb128(p, end);
1063 skip = read_uleb128(p, end);
1064 printf("0x%08X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
1065 break;
1066 default:
1067 throwf("unknown bind opcode %d", *p);
1068 }
1069 }
1070 #endif
1071
1072 template <typename A>
1073 void DyldInfoPrinter<A>::printLazyBindingOpcodes()
1074 {
1075 if ( fInfo == NULL ) {
1076 printf("no compressed dyld info\n");
1077 }
1078 else if ( fInfo->lazy_bind_off() == 0 ) {
1079 printf("no compressed lazy binding info\n");
1080 }
1081 else {
1082 printf("lazy binding opcodes:\n");
1083 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
1084 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
1085 uint8_t type = BIND_TYPE_POINTER;
1086 uint8_t flags;
1087 uint64_t address = fBaseAddress;
1088 const char* symbolName = NULL;
1089 int libraryOrdinal = 0;
1090 int64_t addend = 0;
1091 uint32_t segmentIndex = 0;
1092 uint32_t count;
1093 uint32_t skip;
1094 for (const uint8_t* p = start; p < end; ) {
1095 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1096 uint8_t opcode = *p & BIND_OPCODE_MASK;
1097 uint32_t opcodeOffset = p-start;
1098 ++p;
1099 switch (opcode) {
1100 case BIND_OPCODE_DONE:
1101 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
1102 break;
1103 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1104 libraryOrdinal = immediate;
1105 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1106 break;
1107 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1108 libraryOrdinal = read_uleb128(p, end);
1109 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
1110 break;
1111 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1112 // the special ordinals are negative numbers
1113 if ( immediate == 0 )
1114 libraryOrdinal = 0;
1115 else {
1116 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1117 libraryOrdinal = signExtended;
1118 }
1119 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1120 break;
1121 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1122 flags = immediate;
1123 symbolName = (char*)p;
1124 while (*p != '\0')
1125 ++p;
1126 ++p;
1127 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
1128 break;
1129 case BIND_OPCODE_SET_TYPE_IMM:
1130 type = immediate;
1131 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
1132 break;
1133 case BIND_OPCODE_SET_ADDEND_SLEB:
1134 addend = read_sleb128(p, end);
1135 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
1136 break;
1137 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1138 segmentIndex = immediate;
1139 address = read_uleb128(p, end);
1140 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
1141 break;
1142 case BIND_OPCODE_ADD_ADDR_ULEB:
1143 skip = read_uleb128(p, end);
1144 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1145 break;
1146 case BIND_OPCODE_DO_BIND:
1147 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
1148 break;
1149 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1150 skip = read_uleb128(p, end);
1151 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1152 break;
1153 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1154 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
1155 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
1156 break;
1157 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1158 count = read_uleb128(p, end);
1159 skip = read_uleb128(p, end);
1160 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
1161 break;
1162 default:
1163 throwf("unknown bind opcode %d", *p);
1164 }
1165 }
1166 }
1167
1168 }
1169
1170
1171 template <typename A>
1172 void DyldInfoPrinter<A>::processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end,
1173 char* cummulativeString, int curStrOffset)
1174 {
1175 const uint8_t terminalSize = *p++;
1176 const uint8_t* children = p + terminalSize;
1177 if ( terminalSize != 0 ) {
1178 uint32_t flags = read_uleb128(p, end);
1179 uint64_t address = read_uleb128(p, end);
1180 if ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
1181 fprintf(stdout, "0x%08llX [weak_def] %s\n", address, cummulativeString);
1182 else
1183 fprintf(stdout, "0x%08llX %s\n", address, cummulativeString);
1184 }
1185 const uint8_t childrenCount = *children++;
1186 const uint8_t* s = children;
1187 for (uint8_t i=0; i < childrenCount; ++i) {
1188 int edgeStrLen = 0;
1189 while (*s != '\0') {
1190 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1191 ++edgeStrLen;
1192 }
1193 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1194 uint32_t childNodeOffet = read_uleb128(s, end);
1195 processExportNode(start, start+childNodeOffet, end, cummulativeString, curStrOffset+edgeStrLen);
1196 }
1197 }
1198
1199 struct SortExportsByAddress
1200 {
1201 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
1202 {
1203 return ( left.address < right.address );
1204 }
1205 };
1206
1207 template <typename A>
1208 void DyldInfoPrinter<A>::printExportInfo()
1209 {
1210 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1211 printf("no compressed export info\n");
1212 }
1213 else {
1214 const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
1215 const uint8_t* end = &start[fInfo->export_size()];
1216 std::vector<mach_o::trie::Entry> list;
1217 parseTrie(start, end, list);
1218 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1219 for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) {
1220 const char* flags = "";
1221 if ( it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
1222 flags = "[weak_def] ";
1223 fprintf(stdout, "0x%08llX %s%s\n", fBaseAddress+it->address, flags, it->name);
1224 }
1225 }
1226 }
1227
1228
1229 template <typename A>
1230 void DyldInfoPrinter<A>::processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
1231 const uint8_t* parent, const uint8_t* p,
1232 char* cummulativeString, int curStrOffset)
1233 {
1234 const uint8_t* const me = p;
1235 const uint8_t terminalSize = *p++;
1236 const uint8_t* children = p + terminalSize;
1237 if ( terminalSize != 0 ) {
1238 uint32_t flags = read_uleb128(p, end);
1239 uint64_t address = read_uleb128(p, end);
1240 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address);
1241 }
1242 else {
1243 printf("\tnode%03ld;\n", (long)(me-start));
1244 }
1245 const uint8_t childrenCount = *children++;
1246 const uint8_t* s = children;
1247 for (uint8_t i=0; i < childrenCount; ++i) {
1248 const char* edgeName = (char*)s;
1249 int edgeStrLen = 0;
1250 while (*s != '\0') {
1251 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1252 ++edgeStrLen;
1253 }
1254 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1255 uint32_t childNodeOffet = read_uleb128(s, end);
1256 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me-start), childNodeOffet, edgeName);
1257 processExportGraphNode(start, end, start, start+childNodeOffet, cummulativeString, curStrOffset+edgeStrLen);
1258 }
1259 }
1260
1261 template <typename A>
1262 void DyldInfoPrinter<A>::printExportInfoGraph()
1263 {
1264 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1265 printf("no compressed export info\n");
1266 }
1267 else {
1268 const uint8_t* p = (uint8_t*)fHeader + fInfo->export_off();
1269 const uint8_t* end = &p[fInfo->export_size()];
1270 char cummulativeString[2000];
1271 printf("digraph {\n");
1272 processExportGraphNode(p, end, p, p, cummulativeString, 0);
1273 printf("}\n");
1274 }
1275 }
1276
1277
1278
1279
1280
1281 static void dump(const char* path)
1282 {
1283 struct stat stat_buf;
1284
1285 try {
1286 int fd = ::open(path, O_RDONLY, 0);
1287 if ( fd == -1 )
1288 throw "cannot open file";
1289 if ( ::fstat(fd, &stat_buf) != 0 )
1290 throwf("fstat(%s) failed, errno=%d\n", path, errno);
1291 uint32_t length = stat_buf.st_size;
1292 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
1293 if ( p == ((uint8_t*)(-1)) )
1294 throw "cannot map file";
1295 ::close(fd);
1296 const mach_header* mh = (mach_header*)p;
1297 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
1298 const struct fat_header* fh = (struct fat_header*)p;
1299 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
1300 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
1301 size_t offset = OSSwapBigToHostInt32(archs[i].offset);
1302 size_t size = OSSwapBigToHostInt32(archs[i].size);
1303 cpu_type_t cputype = OSSwapBigToHostInt32(archs[i].cputype);
1304 if ( cputype == (uint32_t)sPreferredArch ) {
1305 switch(cputype) {
1306 case CPU_TYPE_POWERPC:
1307 if ( DyldInfoPrinter<ppc>::validFile(p + offset) )
1308 DyldInfoPrinter<ppc>::make(p + offset, size, path);
1309 else
1310 throw "in universal file, ppc slice does not contain ppc mach-o";
1311 break;
1312 case CPU_TYPE_I386:
1313 if ( DyldInfoPrinter<x86>::validFile(p + offset) )
1314 DyldInfoPrinter<x86>::make(p + offset, size, path);
1315 else
1316 throw "in universal file, i386 slice does not contain i386 mach-o";
1317 break;
1318 case CPU_TYPE_POWERPC64:
1319 if ( DyldInfoPrinter<ppc64>::validFile(p + offset) )
1320 DyldInfoPrinter<ppc64>::make(p + offset, size, path);
1321 else
1322 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
1323 break;
1324 case CPU_TYPE_X86_64:
1325 if ( DyldInfoPrinter<x86_64>::validFile(p + offset) )
1326 DyldInfoPrinter<x86_64>::make(p + offset, size, path);
1327 else
1328 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
1329 break;
1330 case CPU_TYPE_ARM:
1331 if ( DyldInfoPrinter<arm>::validFile(p + offset) )
1332 DyldInfoPrinter<arm>::make(p + offset, size, path);
1333 else
1334 throw "in universal file, arm slice does not contain arm mach-o";
1335 break;
1336 default:
1337 throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
1338 }
1339 }
1340 }
1341 }
1342 else if ( DyldInfoPrinter<x86>::validFile(p) ) {
1343 DyldInfoPrinter<x86>::make(p, length, path);
1344 }
1345 else if ( DyldInfoPrinter<ppc>::validFile(p) ) {
1346 DyldInfoPrinter<ppc>::make(p, length, path);
1347 }
1348 else if ( DyldInfoPrinter<ppc64>::validFile(p) ) {
1349 DyldInfoPrinter<ppc64>::make(p, length, path);
1350 }
1351 else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
1352 DyldInfoPrinter<x86_64>::make(p, length, path);
1353 }
1354 else if ( DyldInfoPrinter<arm>::validFile(p) ) {
1355 DyldInfoPrinter<arm>::make(p, length, path);
1356 }
1357 else {
1358 throw "not a known file type";
1359 }
1360 }
1361 catch (const char* msg) {
1362 throwf("%s in %s", msg, path);
1363 }
1364 }
1365
1366 static void usage()
1367 {
1368 fprintf(stderr, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
1369 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
1370 "\t-bind print addresses dyld will set based on symbolic lookups\n"
1371 "\t-weak_bind print symbols which dyld must coalesce\n"
1372 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
1373 "\t-export print addresses of all symbols this file exports\n"
1374 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
1375 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
1376 );
1377 }
1378
1379
1380 int main(int argc, const char* argv[])
1381 {
1382 if ( argc == 1 ) {
1383 usage();
1384 return 0;
1385 }
1386
1387 try {
1388 std::vector<const char*> files;
1389 for(int i=1; i < argc; ++i) {
1390 const char* arg = argv[i];
1391 if ( arg[0] == '-' ) {
1392 if ( strcmp(arg, "-arch") == 0 ) {
1393 const char* arch = ++i<argc? argv[i]: "";
1394 if ( strcmp(arch, "ppc64") == 0 )
1395 sPreferredArch = CPU_TYPE_POWERPC64;
1396 else if ( strcmp(arch, "ppc") == 0 )
1397 sPreferredArch = CPU_TYPE_POWERPC;
1398 else if ( strcmp(arch, "i386") == 0 )
1399 sPreferredArch = CPU_TYPE_I386;
1400 else if ( strcmp(arch, "x86_64") == 0 )
1401 sPreferredArch = CPU_TYPE_X86_64;
1402 else
1403 throwf("unknown architecture %s", arch);
1404 }
1405 else if ( strcmp(arg, "-rebase") == 0 ) {
1406 printRebase = true;
1407 }
1408 else if ( strcmp(arg, "-bind") == 0 ) {
1409 printBind = true;
1410 }
1411 else if ( strcmp(arg, "-weak_bind") == 0 ) {
1412 printWeakBind = true;
1413 }
1414 else if ( strcmp(arg, "-lazy_bind") == 0 ) {
1415 printLazyBind = true;
1416 }
1417 else if ( strcmp(arg, "-export") == 0 ) {
1418 printExport = true;
1419 }
1420 else if ( strcmp(arg, "-opcodes") == 0 ) {
1421 printOpcodes = true;
1422 }
1423 else if ( strcmp(arg, "-export_dot") == 0 ) {
1424 printExportGraph = true;
1425 }
1426 else {
1427 throwf("unknown option: %s\n", arg);
1428 }
1429 }
1430 else {
1431 files.push_back(arg);
1432 }
1433 }
1434 if ( files.size() == 0 )
1435 usage();
1436 if ( files.size() == 1 ) {
1437 dump(files[0]);
1438 }
1439 else {
1440 for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
1441 printf("\n%s:\n", *it);
1442 dump(*it);
1443 }
1444 }
1445 }
1446 catch (const char* msg) {
1447 fprintf(stderr, "dyldinfo failed: %s\n", msg);
1448 return 1;
1449 }
1450
1451 return 0;
1452 }
1453
1454
1455