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