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