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