]> git.saurik.com Git - apple/ld64.git/blob - src/other/dyldinfo.cpp
016fda3073efb66f3b320f33eb8263d962ed3ad4
[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 weak 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 const char* weak_import = "";
742 bool done = false;
743 while ( !done && (p < end) ) {
744 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
745 uint8_t opcode = *p & BIND_OPCODE_MASK;
746 ++p;
747 switch (opcode) {
748 case BIND_OPCODE_DONE:
749 done = true;
750 break;
751 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
752 libraryOrdinal = immediate;
753 fromDylib = ordinalName(libraryOrdinal);
754 break;
755 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
756 libraryOrdinal = read_uleb128(p, end);
757 fromDylib = ordinalName(libraryOrdinal);
758 break;
759 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
760 // the special ordinals are negative numbers
761 if ( immediate == 0 )
762 libraryOrdinal = 0;
763 else {
764 int8_t signExtended = BIND_OPCODE_MASK | immediate;
765 libraryOrdinal = signExtended;
766 }
767 fromDylib = ordinalName(libraryOrdinal);
768 break;
769 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
770 symbolName = (char*)p;
771 while (*p != '\0')
772 ++p;
773 ++p;
774 if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
775 weak_import = "weak";
776 else
777 weak_import = "";
778 break;
779 case BIND_OPCODE_SET_TYPE_IMM:
780 type = immediate;
781 typeName = bindTypeName(type);
782 break;
783 case BIND_OPCODE_SET_ADDEND_SLEB:
784 addend = read_sleb128(p, end);
785 break;
786 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
787 segIndex = immediate;
788 segStartAddr = segStartAddress(segIndex);
789 segName = segmentName(segIndex);
790 segOffset = read_uleb128(p, end);
791 break;
792 case BIND_OPCODE_ADD_ADDR_ULEB:
793 segOffset += read_uleb128(p, end);
794 break;
795 case BIND_OPCODE_DO_BIND:
796 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
797 segOffset += sizeof(pint_t);
798 break;
799 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
800 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
801 segOffset += read_uleb128(p, end) + sizeof(pint_t);
802 break;
803 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
804 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
805 segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
806 break;
807 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
808 count = read_uleb128(p, end);
809 skip = read_uleb128(p, end);
810 for (uint32_t i=0; i < count; ++i) {
811 printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
812 segOffset += skip + sizeof(pint_t);
813 }
814 break;
815 default:
816 throwf("bad bind opcode %d", *p);
817 }
818 }
819 }
820
821 }
822
823 template <typename A>
824 void DyldInfoPrinter<A>::printWeakBindingInfo()
825 {
826 if ( (fInfo == NULL) || (fInfo->weak_bind_off() == 0) ) {
827 printf("no weak binding\n");
828 }
829 else {
830 printf("weak binding information:\n");
831 printf("segment section address type addend symbol\n");
832 const uint8_t* p = (uint8_t*)fHeader + fInfo->weak_bind_off();
833 const uint8_t* end = &p[fInfo->weak_bind_size()];
834
835 uint8_t type = 0;
836 uint8_t segIndex = 0;
837 uint64_t segOffset = 0;
838 const char* symbolName = NULL;
839 int64_t addend = 0;
840 uint32_t count;
841 uint32_t skip;
842 pint_t segStartAddr = 0;
843 const char* segName = "??";
844 const char* typeName = "??";
845 bool done = false;
846 while ( !done && (p < end) ) {
847 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
848 uint8_t opcode = *p & BIND_OPCODE_MASK;
849 ++p;
850 switch (opcode) {
851 case BIND_OPCODE_DONE:
852 done = true;
853 break;
854 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
855 symbolName = (char*)p;
856 while (*p != '\0')
857 ++p;
858 ++p;
859 if ( (immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) != 0 )
860 printf(" strong %s\n", symbolName );
861 break;
862 case BIND_OPCODE_SET_TYPE_IMM:
863 type = immediate;
864 typeName = bindTypeName(type);
865 break;
866 case BIND_OPCODE_SET_ADDEND_SLEB:
867 addend = read_sleb128(p, end);
868 break;
869 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
870 segIndex = immediate;
871 segStartAddr = segStartAddress(segIndex);
872 segName = segmentName(segIndex);
873 segOffset = read_uleb128(p, end);
874 break;
875 case BIND_OPCODE_ADD_ADDR_ULEB:
876 segOffset += read_uleb128(p, end);
877 break;
878 case BIND_OPCODE_DO_BIND:
879 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
880 segOffset += sizeof(pint_t);
881 break;
882 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
883 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
884 segOffset += read_uleb128(p, end) + sizeof(pint_t);
885 break;
886 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
887 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
888 segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
889 break;
890 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
891 count = read_uleb128(p, end);
892 skip = read_uleb128(p, end);
893 for (uint32_t i=0; i < count; ++i) {
894 printf("%-7s %-16s 0x%08llX %10s %5lld %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, symbolName );
895 segOffset += skip + sizeof(pint_t);
896 }
897 break;
898 default:
899 throwf("unknown weak bind opcode %d", *p);
900 }
901 }
902 }
903
904 }
905
906
907 template <typename A>
908 void DyldInfoPrinter<A>::printLazyBindingInfo()
909 {
910 if ( fInfo == NULL ) {
911 printf("no compressed dyld info\n");
912 }
913 else if ( fInfo->lazy_bind_off() == 0 ) {
914 printf("no compressed lazy binding info\n");
915 }
916 else {
917 printf("lazy binding information:\n");
918 printf("segment section address index dylib symbol\n");
919 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
920 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
921
922 uint8_t type = BIND_TYPE_POINTER;
923 uint8_t segIndex = 0;
924 uint64_t segOffset = 0;
925 const char* symbolName = NULL;
926 const char* fromDylib = "??";
927 int libraryOrdinal = 0;
928 int64_t addend = 0;
929 uint32_t lazy_offset = 0;
930 pint_t segStartAddr = 0;
931 const char* segName = "??";
932 const char* typeName = "??";
933 for (const uint8_t* p=start; p < end; ) {
934 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
935 uint8_t opcode = *p & BIND_OPCODE_MASK;
936 ++p;
937 switch (opcode) {
938 case BIND_OPCODE_DONE:
939 lazy_offset = p-start;
940 break;
941 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
942 libraryOrdinal = immediate;
943 fromDylib = ordinalName(libraryOrdinal);
944 break;
945 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
946 libraryOrdinal = read_uleb128(p, end);
947 fromDylib = ordinalName(libraryOrdinal);
948 break;
949 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
950 // the special ordinals are negative numbers
951 if ( immediate == 0 )
952 libraryOrdinal = 0;
953 else {
954 int8_t signExtended = BIND_OPCODE_MASK | immediate;
955 libraryOrdinal = signExtended;
956 }
957 fromDylib = ordinalName(libraryOrdinal);
958 break;
959 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
960 symbolName = (char*)p;
961 while (*p != '\0')
962 ++p;
963 ++p;
964 break;
965 case BIND_OPCODE_SET_TYPE_IMM:
966 type = immediate;
967 typeName = bindTypeName(type);
968 break;
969 case BIND_OPCODE_SET_ADDEND_SLEB:
970 addend = read_sleb128(p, end);
971 break;
972 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
973 segIndex = immediate;
974 segStartAddr = segStartAddress(segIndex);
975 segName = segmentName(segIndex);
976 segOffset = read_uleb128(p, end);
977 break;
978 case BIND_OPCODE_ADD_ADDR_ULEB:
979 segOffset += read_uleb128(p, end);
980 break;
981 case BIND_OPCODE_DO_BIND:
982 printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName );
983 segOffset += sizeof(pint_t);
984 break;
985 default:
986 throwf("bad lazy bind opcode %d", *p);
987 }
988 }
989 }
990
991 }
992
993 #if 0
994 uint8_t type = BIND_TYPE_POINTER;
995 uint8_t flags;
996 uint64_t address = fBaseAddress;
997 const char* symbolName = NULL;
998 int libraryOrdinal = 0;
999 int64_t addend = 0;
1000 uint32_t segmentIndex = 0;
1001 uint32_t count;
1002 uint32_t skip;
1003 for (const uint8_t* p = start; p < end; ) {
1004 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1005 uint8_t opcode = *p & BIND_OPCODE_MASK;
1006 uint32_t opcodeOffset = p-start;
1007 ++p;
1008 switch (opcode) {
1009 case BIND_OPCODE_DONE:
1010 printf("0x%08X BIND_OPCODE_DONE\n", opcodeOffset);
1011 break;
1012 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1013 libraryOrdinal = immediate;
1014 printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1015 break;
1016 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1017 libraryOrdinal = read_uleb128(p, end);
1018 printf("0x%08X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
1019 break;
1020 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1021 // the special ordinals are negative numbers
1022 if ( immediate == 0 )
1023 libraryOrdinal = 0;
1024 else {
1025 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1026 libraryOrdinal = signExtended;
1027 }
1028 printf("0x%08X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1029 break;
1030 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1031 flags = immediate;
1032 symbolName = (char*)p;
1033 while (*p != '\0')
1034 ++p;
1035 ++p;
1036 printf("0x%08X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
1037 break;
1038 case BIND_OPCODE_SET_TYPE_IMM:
1039 type = immediate;
1040 printf("0x%08X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
1041 break;
1042 case BIND_OPCODE_SET_ADDEND_SLEB:
1043 addend = read_sleb128(p, end);
1044 printf("0x%08X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
1045 break;
1046 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1047 segmentIndex = immediate;
1048 address = read_uleb128(p, end);
1049 printf("0x%08X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
1050 break;
1051 case BIND_OPCODE_ADD_ADDR_ULEB:
1052 skip = read_uleb128(p, end);
1053 printf("0x%08X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1054 break;
1055 case BIND_OPCODE_DO_BIND:
1056 printf("0x%08X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
1057 break;
1058 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1059 skip = read_uleb128(p, end);
1060 printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1061 break;
1062 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1063 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
1064 printf("0x%08X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
1065 break;
1066 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1067 count = read_uleb128(p, end);
1068 skip = read_uleb128(p, end);
1069 printf("0x%08X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
1070 break;
1071 default:
1072 throwf("unknown bind opcode %d", *p);
1073 }
1074 }
1075 #endif
1076
1077 template <typename A>
1078 void DyldInfoPrinter<A>::printLazyBindingOpcodes()
1079 {
1080 if ( fInfo == NULL ) {
1081 printf("no compressed dyld info\n");
1082 }
1083 else if ( fInfo->lazy_bind_off() == 0 ) {
1084 printf("no compressed lazy binding info\n");
1085 }
1086 else {
1087 printf("lazy binding opcodes:\n");
1088 const uint8_t* const start = (uint8_t*)fHeader + fInfo->lazy_bind_off();
1089 const uint8_t* const end = &start[fInfo->lazy_bind_size()];
1090 uint8_t type = BIND_TYPE_POINTER;
1091 uint8_t flags;
1092 uint64_t address = fBaseAddress;
1093 const char* symbolName = NULL;
1094 int libraryOrdinal = 0;
1095 int64_t addend = 0;
1096 uint32_t segmentIndex = 0;
1097 uint32_t count;
1098 uint32_t skip;
1099 for (const uint8_t* p = start; p < end; ) {
1100 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1101 uint8_t opcode = *p & BIND_OPCODE_MASK;
1102 uint32_t opcodeOffset = p-start;
1103 ++p;
1104 switch (opcode) {
1105 case BIND_OPCODE_DONE:
1106 printf("0x%04X BIND_OPCODE_DONE\n", opcodeOffset);
1107 break;
1108 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1109 libraryOrdinal = immediate;
1110 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1111 break;
1112 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1113 libraryOrdinal = read_uleb128(p, end);
1114 printf("0x%04X BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%d)\n", opcodeOffset, libraryOrdinal);
1115 break;
1116 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1117 // the special ordinals are negative numbers
1118 if ( immediate == 0 )
1119 libraryOrdinal = 0;
1120 else {
1121 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1122 libraryOrdinal = signExtended;
1123 }
1124 printf("0x%04X BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%d)\n", opcodeOffset, libraryOrdinal);
1125 break;
1126 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1127 flags = immediate;
1128 symbolName = (char*)p;
1129 while (*p != '\0')
1130 ++p;
1131 ++p;
1132 printf("0x%04X BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%02X, %s)\n", opcodeOffset, flags, symbolName);
1133 break;
1134 case BIND_OPCODE_SET_TYPE_IMM:
1135 type = immediate;
1136 printf("0x%04X BIND_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
1137 break;
1138 case BIND_OPCODE_SET_ADDEND_SLEB:
1139 addend = read_sleb128(p, end);
1140 printf("0x%04X BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", opcodeOffset, addend);
1141 break;
1142 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1143 segmentIndex = immediate;
1144 address = read_uleb128(p, end);
1145 printf("0x%04X BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x%02X, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
1146 break;
1147 case BIND_OPCODE_ADD_ADDR_ULEB:
1148 skip = read_uleb128(p, end);
1149 printf("0x%04X BIND_OPCODE_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1150 break;
1151 case BIND_OPCODE_DO_BIND:
1152 printf("0x%04X BIND_OPCODE_DO_BIND()\n", opcodeOffset);
1153 break;
1154 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1155 skip = read_uleb128(p, end);
1156 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%08X)\n", opcodeOffset, skip);
1157 break;
1158 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1159 skip = immediate*sizeof(pint_t) + sizeof(pint_t);
1160 printf("0x%04X BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(0x%08X)\n", opcodeOffset, skip);
1161 break;
1162 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1163 count = read_uleb128(p, end);
1164 skip = read_uleb128(p, end);
1165 printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
1166 break;
1167 default:
1168 throwf("unknown bind opcode %d", *p);
1169 }
1170 }
1171 }
1172
1173 }
1174
1175
1176 template <typename A>
1177 void DyldInfoPrinter<A>::processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end,
1178 char* cummulativeString, int curStrOffset)
1179 {
1180 const uint8_t terminalSize = *p++;
1181 const uint8_t* children = p + terminalSize;
1182 if ( terminalSize != 0 ) {
1183 uint32_t flags = read_uleb128(p, end);
1184 uint64_t address = read_uleb128(p, end);
1185 if ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
1186 fprintf(stdout, "0x%08llX [weak_def] %s\n", address, cummulativeString);
1187 else
1188 fprintf(stdout, "0x%08llX %s\n", address, cummulativeString);
1189 }
1190 const uint8_t childrenCount = *children++;
1191 const uint8_t* s = children;
1192 for (uint8_t i=0; i < childrenCount; ++i) {
1193 int edgeStrLen = 0;
1194 while (*s != '\0') {
1195 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1196 ++edgeStrLen;
1197 }
1198 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1199 uint32_t childNodeOffet = read_uleb128(s, end);
1200 processExportNode(start, start+childNodeOffet, end, cummulativeString, curStrOffset+edgeStrLen);
1201 }
1202 }
1203
1204 struct SortExportsByAddress
1205 {
1206 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
1207 {
1208 return ( left.address < right.address );
1209 }
1210 };
1211
1212 template <typename A>
1213 void DyldInfoPrinter<A>::printExportInfo()
1214 {
1215 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1216 printf("no compressed export info\n");
1217 }
1218 else {
1219 const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
1220 const uint8_t* end = &start[fInfo->export_size()];
1221 std::vector<mach_o::trie::Entry> list;
1222 parseTrie(start, end, list);
1223 //std::sort(list.begin(), list.end(), SortExportsByAddress());
1224 for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) {
1225 const char* flags = "";
1226 if ( it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
1227 flags = "[weak_def] ";
1228 fprintf(stdout, "0x%08llX %s%s\n", fBaseAddress+it->address, flags, it->name);
1229 }
1230 }
1231 }
1232
1233
1234 template <typename A>
1235 void DyldInfoPrinter<A>::processExportGraphNode(const uint8_t* const start, const uint8_t* const end,
1236 const uint8_t* parent, const uint8_t* p,
1237 char* cummulativeString, int curStrOffset)
1238 {
1239 const uint8_t* const me = p;
1240 const uint8_t terminalSize = *p++;
1241 const uint8_t* children = p + terminalSize;
1242 if ( terminalSize != 0 ) {
1243 uint32_t flags = read_uleb128(p, end);
1244 uint64_t address = read_uleb128(p, end);
1245 printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address);
1246 }
1247 else {
1248 printf("\tnode%03ld;\n", (long)(me-start));
1249 }
1250 const uint8_t childrenCount = *children++;
1251 const uint8_t* s = children;
1252 for (uint8_t i=0; i < childrenCount; ++i) {
1253 const char* edgeName = (char*)s;
1254 int edgeStrLen = 0;
1255 while (*s != '\0') {
1256 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1257 ++edgeStrLen;
1258 }
1259 cummulativeString[curStrOffset+edgeStrLen] = *s++;
1260 uint32_t childNodeOffet = read_uleb128(s, end);
1261 printf("\tnode%03ld -> node%03d [ label=%s ] ;\n", (long)(me-start), childNodeOffet, edgeName);
1262 processExportGraphNode(start, end, start, start+childNodeOffet, cummulativeString, curStrOffset+edgeStrLen);
1263 }
1264 }
1265
1266 template <typename A>
1267 void DyldInfoPrinter<A>::printExportInfoGraph()
1268 {
1269 if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
1270 printf("no compressed export info\n");
1271 }
1272 else {
1273 const uint8_t* p = (uint8_t*)fHeader + fInfo->export_off();
1274 const uint8_t* end = &p[fInfo->export_size()];
1275 char cummulativeString[2000];
1276 printf("digraph {\n");
1277 processExportGraphNode(p, end, p, p, cummulativeString, 0);
1278 printf("}\n");
1279 }
1280 }
1281
1282
1283
1284
1285
1286 static void dump(const char* path)
1287 {
1288 struct stat stat_buf;
1289
1290 try {
1291 int fd = ::open(path, O_RDONLY, 0);
1292 if ( fd == -1 )
1293 throw "cannot open file";
1294 if ( ::fstat(fd, &stat_buf) != 0 )
1295 throwf("fstat(%s) failed, errno=%d\n", path, errno);
1296 uint32_t length = stat_buf.st_size;
1297 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
1298 if ( p == ((uint8_t*)(-1)) )
1299 throw "cannot map file";
1300 ::close(fd);
1301 const mach_header* mh = (mach_header*)p;
1302 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
1303 const struct fat_header* fh = (struct fat_header*)p;
1304 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
1305 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
1306 size_t offset = OSSwapBigToHostInt32(archs[i].offset);
1307 size_t size = OSSwapBigToHostInt32(archs[i].size);
1308 cpu_type_t cputype = OSSwapBigToHostInt32(archs[i].cputype);
1309 if ( cputype == (uint32_t)sPreferredArch ) {
1310 switch(cputype) {
1311 case CPU_TYPE_POWERPC:
1312 if ( DyldInfoPrinter<ppc>::validFile(p + offset) )
1313 DyldInfoPrinter<ppc>::make(p + offset, size, path);
1314 else
1315 throw "in universal file, ppc slice does not contain ppc mach-o";
1316 break;
1317 case CPU_TYPE_I386:
1318 if ( DyldInfoPrinter<x86>::validFile(p + offset) )
1319 DyldInfoPrinter<x86>::make(p + offset, size, path);
1320 else
1321 throw "in universal file, i386 slice does not contain i386 mach-o";
1322 break;
1323 case CPU_TYPE_POWERPC64:
1324 if ( DyldInfoPrinter<ppc64>::validFile(p + offset) )
1325 DyldInfoPrinter<ppc64>::make(p + offset, size, path);
1326 else
1327 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
1328 break;
1329 case CPU_TYPE_X86_64:
1330 if ( DyldInfoPrinter<x86_64>::validFile(p + offset) )
1331 DyldInfoPrinter<x86_64>::make(p + offset, size, path);
1332 else
1333 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
1334 break;
1335 case CPU_TYPE_ARM:
1336 if ( DyldInfoPrinter<arm>::validFile(p + offset) )
1337 DyldInfoPrinter<arm>::make(p + offset, size, path);
1338 else
1339 throw "in universal file, arm slice does not contain arm mach-o";
1340 break;
1341 default:
1342 throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
1343 }
1344 }
1345 }
1346 }
1347 else if ( DyldInfoPrinter<x86>::validFile(p) ) {
1348 DyldInfoPrinter<x86>::make(p, length, path);
1349 }
1350 else if ( DyldInfoPrinter<ppc>::validFile(p) ) {
1351 DyldInfoPrinter<ppc>::make(p, length, path);
1352 }
1353 else if ( DyldInfoPrinter<ppc64>::validFile(p) ) {
1354 DyldInfoPrinter<ppc64>::make(p, length, path);
1355 }
1356 else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
1357 DyldInfoPrinter<x86_64>::make(p, length, path);
1358 }
1359 else if ( DyldInfoPrinter<arm>::validFile(p) ) {
1360 DyldInfoPrinter<arm>::make(p, length, path);
1361 }
1362 else {
1363 throw "not a known file type";
1364 }
1365 }
1366 catch (const char* msg) {
1367 throwf("%s in %s", msg, path);
1368 }
1369 }
1370
1371 static void usage()
1372 {
1373 fprintf(stderr, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
1374 "\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
1375 "\t-bind print addresses dyld will set based on symbolic lookups\n"
1376 "\t-weak_bind print symbols which dyld must coalesce\n"
1377 "\t-lazy_bind print addresses dyld will lazily set on first use\n"
1378 "\t-export print addresses of all symbols this file exports\n"
1379 "\t-opcodes print opcodes used to generate the rebase and binding information\n"
1380 "\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
1381 );
1382 }
1383
1384
1385 int main(int argc, const char* argv[])
1386 {
1387 if ( argc == 1 ) {
1388 usage();
1389 return 0;
1390 }
1391
1392 try {
1393 std::vector<const char*> files;
1394 for(int i=1; i < argc; ++i) {
1395 const char* arg = argv[i];
1396 if ( arg[0] == '-' ) {
1397 if ( strcmp(arg, "-arch") == 0 ) {
1398 const char* arch = ++i<argc? argv[i]: "";
1399 if ( strcmp(arch, "ppc64") == 0 )
1400 sPreferredArch = CPU_TYPE_POWERPC64;
1401 else if ( strcmp(arch, "ppc") == 0 )
1402 sPreferredArch = CPU_TYPE_POWERPC;
1403 else if ( strcmp(arch, "i386") == 0 )
1404 sPreferredArch = CPU_TYPE_I386;
1405 else if ( strcmp(arch, "x86_64") == 0 )
1406 sPreferredArch = CPU_TYPE_X86_64;
1407 else
1408 throwf("unknown architecture %s", arch);
1409 }
1410 else if ( strcmp(arg, "-rebase") == 0 ) {
1411 printRebase = true;
1412 }
1413 else if ( strcmp(arg, "-bind") == 0 ) {
1414 printBind = true;
1415 }
1416 else if ( strcmp(arg, "-weak_bind") == 0 ) {
1417 printWeakBind = true;
1418 }
1419 else if ( strcmp(arg, "-lazy_bind") == 0 ) {
1420 printLazyBind = true;
1421 }
1422 else if ( strcmp(arg, "-export") == 0 ) {
1423 printExport = true;
1424 }
1425 else if ( strcmp(arg, "-opcodes") == 0 ) {
1426 printOpcodes = true;
1427 }
1428 else if ( strcmp(arg, "-export_dot") == 0 ) {
1429 printExportGraph = true;
1430 }
1431 else {
1432 throwf("unknown option: %s\n", arg);
1433 }
1434 }
1435 else {
1436 files.push_back(arg);
1437 }
1438 }
1439 if ( files.size() == 0 )
1440 usage();
1441 if ( files.size() == 1 ) {
1442 dump(files[0]);
1443 }
1444 else {
1445 for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
1446 printf("\n%s:\n", *it);
1447 dump(*it);
1448 }
1449 }
1450 }
1451 catch (const char* msg) {
1452 fprintf(stderr, "dyldinfo failed: %s\n", msg);
1453 return 1;
1454 }
1455
1456 return 0;
1457 }
1458
1459
1460