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