1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2018-2019 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
37 #include <unordered_set>
41 #include "MachOFile.h"
42 #include "MachOLoaded.h"
43 #include "MachOAnalyzer.h"
44 #include "ClosureFileSystemPhysical.h"
47 static void versionToString(uint32_t value
, char buffer
[32])
50 strcpy(buffer
, "n/a");
51 else if ( value
& 0xFF )
52 sprintf(buffer
, "%d.%d.%d", value
>> 16, (value
>> 8) & 0xFF, value
& 0xFF);
54 sprintf(buffer
, "%d.%d", value
>> 16, (value
>> 8) & 0xFF);
57 static void printPlatforms(const dyld3
::MachOAnalyzer
* ma
)
59 printf(" -platform:\n");
60 printf(" platform minOS sdk\n");
61 ma
->forEachSupportedPlatform(^(dyld3
::Platform platform
, uint32_t minOS
, uint32_t sdk
) {
64 versionToString(minOS
, osVers
);
65 versionToString(sdk
, sdkVers
);
66 printf(" %15s %-7s %-7s\n", dyld3
::MachOFile
::platformName(platform
), osVers
, sdkVers
);
70 static void printSegments(const dyld3
::MachOAnalyzer
* ma
)
72 printf(" -segments:\n");
73 printf(" load-offset segment section sect-size seg-size perm\n");
74 __block
const char* lastSegName
= "";
75 __block
uint64_t firstSegVmAddr
= 0;
76 ma
->forEachSection(^(const dyld3
::MachOFile
::SectionInfo
& sectInfo
, bool malformedSectionRange
, bool& stop
) {
77 if ( lastSegName
[0] == '\0' )
78 firstSegVmAddr
= sectInfo
.segInfo
.vmAddr
;
79 if ( strcmp(lastSegName
, sectInfo
.segInfo
.segName
) != 0 ) {
80 char r
= (sectInfo
.segInfo
.protections
& VM_PROT_READ
) ?
'r' : '.';
81 char w
= (sectInfo
.segInfo
.protections
& VM_PROT_WRITE
) ?
'w' : '.';
82 char x
= (sectInfo
.segInfo
.protections
& VM_PROT_EXECUTE
) ?
'x' : '.';
83 printf(" 0x%08llX %-12s %6lluKB %c%c%c\n", sectInfo
.segInfo
.vmAddr
- firstSegVmAddr
, sectInfo
.segInfo
.segName
, sectInfo
.segInfo
.vmSize
/1024, r
, w
, x
);
84 lastSegName
= sectInfo
.segInfo
.segName
;
86 printf(" 0x%08llX %-16s %6llu\n", sectInfo
.sectAddr
-firstSegVmAddr
, sectInfo
.sectName
, sectInfo
.sectSize
);
93 static void printDependents(const dyld3
::MachOAnalyzer
* ma
)
95 printf(" -dependents:\n");
96 printf(" attributes load path\n");
97 ma
->forEachDependentDylib(^(const char* loadPath
, bool isWeak
, bool isReExport
, bool isUpward
, uint32_t compatVersion
, uint32_t curVersion
, bool &stop
) {
98 const char* attribute
= "";
100 attribute
= "weak_import";
101 else if ( isReExport
)
102 attribute
= "re-export";
104 attribute
= "upward";
105 printf(" %-12s %s\n", attribute
, loadPath
);
109 static const char* rebaseTypeName(uint8_t type
)
112 case REBASE_TYPE_POINTER
:
113 return "rebase pointer";
114 case REBASE_TYPE_TEXT_ABSOLUTE32
:
115 return "rebase text abs32";
116 case REBASE_TYPE_TEXT_PCREL32
:
117 return "rebase text rel32";
119 return "!!unknown!!";
122 static const char* bindTypeName(uint8_t type
)
125 case BIND_TYPE_POINTER
:
126 return "bind pointer";
127 case BIND_TYPE_TEXT_ABSOLUTE32
:
128 return "bind text abs32";
129 case BIND_TYPE_TEXT_PCREL32
:
130 return "bind text rel32";
132 return "!!unknown!!";
135 static const char* pointerFormat(uint16_t format
)
138 case DYLD_CHAINED_PTR_ARM64E
:
139 return "authenticated arm64e";
140 case DYLD_CHAINED_PTR_ARM64E_OFFSET
:
141 return "authenticated arm64e offset";
142 case DYLD_CHAINED_PTR_64
:
143 return "generic 64-bit";
144 case DYLD_CHAINED_PTR_64_OFFSET
:
145 return "generic 64-bit offset";
146 case DYLD_CHAINED_PTR_32
:
147 return "generic 32-bit";
148 case DYLD_CHAINED_PTR_32_CACHE
:
149 return "32-bit for dyld cache";
154 static void printChains(const dyld3
::MachOAnalyzer
* ma
)
157 ma
->withChainStarts(diag
, 0, ^(const dyld_chained_starts_in_image
* starts
) {
158 for (int i
=0; i
< starts
->seg_count
; ++i
) {
159 if ( starts
->seg_info_offset
[i
] == 0 )
161 const dyld_chained_starts_in_segment
* seg
= (dyld_chained_starts_in_segment
*)((uint8_t*)starts
+ starts
->seg_info_offset
[i
]);
162 if ( seg
->page_count
== 0 )
164 printf("seg[%d]:\n", i
);
165 printf(" page_size: 0x%04X\n", seg
->page_size
);
166 printf(" pointer_format: %d (%s)\n", seg
->pointer_format
, pointerFormat(seg
->pointer_format
));
167 printf(" segment_offset: 0x%08llX\n", seg
->segment_offset
);
168 printf(" max_pointer: 0x%08X\n", seg
->max_valid_pointer
);
169 printf(" pages: %d\n", seg
->page_count
);
170 for (int pageIndex
=0; pageIndex
< seg
->page_count
; ++pageIndex
) {
171 uint16_t offsetInPage
= seg
->page_start
[pageIndex
];
172 if ( offsetInPage
== DYLD_CHAINED_PTR_START_NONE
)
174 if ( offsetInPage
& DYLD_CHAINED_PTR_START_MULTI
) {
175 // 32-bit chains which may need multiple starts per page
176 uint32_t overflowIndex
= offsetInPage
& ~DYLD_CHAINED_PTR_START_MULTI
;
177 bool chainEnd
= false;
179 chainEnd
= (seg
->page_start
[overflowIndex
] & DYLD_CHAINED_PTR_START_LAST
);
180 offsetInPage
= (seg
->page_start
[overflowIndex
] & ~DYLD_CHAINED_PTR_START_LAST
);
181 printf(" start[% 2d]: 0x%04X\n", pageIndex
, offsetInPage
);
186 // one chain per page
187 printf(" start[% 2d]: 0x%04X\n", pageIndex
, offsetInPage
);
195 static void printChainDetails(const dyld3
::MachOAnalyzer
* ma
)
197 __block Diagnostics diag
;
198 ma
->withChainStarts(diag
, 0, ^(const dyld_chained_starts_in_image
* starts
) {
199 ma
->forEachFixupInAllChains(diag
, starts
, true, ^(dyld3
::MachOLoaded
::ChainedFixupPointerOnDisk
* fixupLoc
, const dyld_chained_starts_in_segment
* segInfo
, bool& stop
) {
200 uint64_t vmOffset
= (uint8_t*)fixupLoc
- (uint8_t*)ma
;
201 switch (segInfo
->pointer_format
) {
202 case DYLD_CHAINED_PTR_ARM64E
:
203 case DYLD_CHAINED_PTR_ARM64E_OFFSET
:
204 if ( fixupLoc
->arm64e
.authRebase
.auth
) {
205 if ( fixupLoc
->arm64e
.authBind
.bind
) {
206 printf(" 0x%08llX: raw: 0x%016llX auth-bind: (next: %03d, key: %s, addrDiv: %d, diversity: 0x%04X, ordinal: %04X)\n", vmOffset
, fixupLoc
->raw64
,
207 fixupLoc
->arm64e
.authBind
.next
, fixupLoc
->arm64e
.keyName(),
208 fixupLoc
->arm64e
.authBind
.addrDiv
, fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authBind
.ordinal
);
211 printf(" 0x%08llX: raw: 0x%016llX auth-rebase: (next: %03d, key: %s, addrDiv: %d, diversity: 0x%04X, target: 0x%08X)\n", vmOffset
, fixupLoc
->raw64
,
212 fixupLoc
->arm64e
.authRebase
.next
, fixupLoc
->arm64e
.keyName(),
213 fixupLoc
->arm64e
.authBind
.addrDiv
, fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authRebase
.target
);
217 if ( fixupLoc
->arm64e
.rebase
.bind
) {
218 printf(" 0x%08llX: raw: 0x%016llX bind: (next: %03d, ordinal: %04X, addend: %d)\n", vmOffset
, fixupLoc
->raw64
,
219 fixupLoc
->arm64e
.bind
.next
, fixupLoc
->arm64e
.bind
.ordinal
, fixupLoc
->arm64e
.bind
.addend
);
222 printf(" 0x%08llX: raw: 0x%016llX rebase: (next: %03d, target: 0x%011llX, high8: 0x%02X)\n", vmOffset
, fixupLoc
->raw64
,
223 fixupLoc
->arm64e
.rebase
.next
, fixupLoc
->arm64e
.rebase
.target
, fixupLoc
->arm64e
.rebase
.high8
);
227 case DYLD_CHAINED_PTR_64
:
228 case DYLD_CHAINED_PTR_64_OFFSET
:
229 if ( fixupLoc
->generic64
.rebase
.bind
) {
230 printf(" 0x%08llX: raw: 0x%016llX bind: (next: %03d, ordinal: %06X, addend: %d)\n", vmOffset
, fixupLoc
->raw64
,
231 fixupLoc
->generic64
.bind
.next
, fixupLoc
->generic64
.bind
.ordinal
, fixupLoc
->generic64
.bind
.addend
);
234 printf(" 0x%08llX: raw: 0x%016llX rebase: (next: %03d, target: 0x%011llX, high8: 0x%02X)\n", vmOffset
, fixupLoc
->raw64
,
235 fixupLoc
->generic64
.rebase
.next
, fixupLoc
->generic64
.rebase
.target
, fixupLoc
->generic64
.rebase
.high8
);
238 case DYLD_CHAINED_PTR_32
:
239 if ( fixupLoc
->generic32
.bind
.bind
) {
240 printf(" 0x%08llX: raw: 0x%08X bind: (next:%02d ordinal:%05X addend:%d)\n", vmOffset
, fixupLoc
->raw32
,
241 fixupLoc
->generic32
.bind
.next
, fixupLoc
->generic32
.bind
.ordinal
, fixupLoc
->generic32
.bind
.addend
);
243 else if ( fixupLoc
->generic32
.rebase
.target
> segInfo
->max_valid_pointer
) {
244 uint32_t bias
= (0x04000000 + segInfo
->max_valid_pointer
)/2;
245 uint32_t value
= fixupLoc
->generic32
.rebase
.target
- bias
;
246 printf(" 0x%08llX: raw: 0x%08X nonptr: (next:%02d value: 0x%08X)\n", vmOffset
, fixupLoc
->raw32
,
247 fixupLoc
->generic32
.rebase
.next
, value
);
250 printf(" 0x%08llX: raw: 0x%08X rebase: (next:%02d target: 0x%07X)\n", vmOffset
, fixupLoc
->raw32
,
251 fixupLoc
->generic32
.rebase
.next
, fixupLoc
->generic32
.rebase
.target
);
255 fprintf(stderr
, "unknown pointer type %d\n", segInfo
->pointer_format
);
260 if ( diag
.hasError() )
261 fprintf(stderr
, "dyldinfo: %s\n", diag
.errorMessage());
268 std
::string sectName
;
271 uint64_t targetValue
;
272 const char* targetDylib
;
273 const char* targetSymbolName
;
274 uint64_t targetAddend
;
275 bool targetWeakImport
;
280 static const char* ordinalName(const dyld3
::MachOAnalyzer
* ma
, int libraryOrdinal
)
282 static int sLastOrdinal
= -100;
283 static const char* sLastString
= nullptr;
284 if ( libraryOrdinal
> 0 ) {
285 if ( libraryOrdinal
!= sLastOrdinal
) {
286 const char* path
= ma
->dependentDylibLoadPath(libraryOrdinal
-1);
287 if ( path
== nullptr )
288 return "ordinal-too-large";
289 const char* leafName
= path
;
290 if ( const char* lastSlash
= strrchr(path
, '/') )
291 leafName
= lastSlash
+1;
292 sLastOrdinal
= libraryOrdinal
;
293 sLastString
= leafName
;
298 switch ( libraryOrdinal
) {
299 case BIND_SPECIAL_DYLIB_SELF
:
301 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
302 return "main-executable";
303 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
304 return "flat-namespace";
305 case BIND_SPECIAL_DYLIB_WEAK_LOOKUP
:
306 return "weak-coalesce";
309 return "unknown-ordinal";
316 SectionFinder(const dyld3
::MachOAnalyzer
* ma
);
317 const char* segmentName(uint64_t vmOffset
) const;
318 const char* sectionName(uint64_t vmOffset
) const;
319 uint64_t baseAddress() const { return _baseAddress
; }
320 uint64_t currentSectionAddress() const { return _lastSection
.sectAddr
; }
321 bool isNewSection(uint64_t vmOffset
) const;
324 void updateLastSection(uint64_t vmOffset
) const;
326 const dyld3
::MachOAnalyzer
* _ma
;
327 uint64_t _baseAddress
;
328 mutable dyld3
::MachOFile
::SectionInfo _lastSection
;
329 mutable char _lastSectName
[20];
332 SectionFinder
::SectionFinder(const dyld3
::MachOAnalyzer
* ma
)
335 _baseAddress
= ma
->preferredLoadAddress();
336 _lastSection
.sectAddr
= 0;
337 _lastSection
.sectSize
= 0;
340 bool SectionFinder
::isNewSection(uint64_t vmOffset
) const
342 uint64_t vmAddr
= _baseAddress
+ vmOffset
;
343 return ( (vmAddr
< _lastSection
.sectAddr
) || (vmAddr
>= _lastSection
.sectAddr
+_lastSection
.sectSize
) );
346 void SectionFinder
::updateLastSection(uint64_t vmOffset
) const
348 if ( isNewSection(vmOffset
) ) {
349 uint64_t vmAddr
= _baseAddress
+ vmOffset
;
350 _ma
->forEachSection(^(const dyld3
::MachOFile
::SectionInfo
& sectInfo
, bool malformedSectionRange
, bool& sectStop
) {
351 if ( (sectInfo
.sectAddr
<= vmAddr
) && (vmAddr
< sectInfo
.sectAddr
+sectInfo
.sectSize
) ) {
352 _lastSection
= sectInfo
;
353 strcpy(_lastSectName
, _lastSection
.sectName
);
360 const char* SectionFinder
::segmentName(uint64_t vmOffset
) const
362 updateLastSection(vmOffset
);
363 return _lastSection
.segInfo
.segName
;
366 const char* SectionFinder
::sectionName(uint64_t vmOffset
) const
368 updateLastSection(vmOffset
);
369 return _lastSectName
;
374 static void printPreloadChainedFixups(const dyld3
::MachOAnalyzer
* ma
)
376 printf(" segment section address type (dvrsty addr key) target\n");
377 SectionFinder
namer(ma
);
378 uint64_t sectionSize
;
379 const dyld_chained_starts_offsets
* startsSection
= (dyld_chained_starts_offsets
*)ma
->findSectionContent("__TEXT", "__chain_starts", sectionSize
);
380 if ( startsSection
!= nullptr ) {
381 switch (startsSection
->pointer_format
) {
382 case DYLD_CHAINED_PTR_32_FIRMWARE
:
383 for (uint32_t startIndex
=0; startIndex
< startsSection
->starts_count
; ++startIndex
) {
384 const dyld_chained_ptr_32_firmware_rebase
* p
= (dyld_chained_ptr_32_firmware_rebase
*)(((uint8_t*)ma
)+ startsSection
->chain_starts
[startIndex
]);
387 uint64_t vmOffset
= ((uint8_t*)p
- (uint8_t*)ma
);
388 printf(" %-12s %-16s 0x%08llX %16s 0x%08X\n",
389 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), namer
.baseAddress()+vmOffset
,
390 "rebase pointer", p
->target
);
391 done
= (p
->next
== 0);
406 const char* symbolName
;
412 static void printChainedFixups(const dyld3
::MachOAnalyzer
* ma
)
414 // build array of targets
415 __block Diagnostics diag
;
416 __block std
::vector
<FixupTarget
> targets
;
417 ma
->forEachChainedFixupTarget(diag
, ^(int libOrdinal
, const char* symbolName
, uint64_t addend
, bool weakImport
, bool& stop
) {
420 target
.dylib
= ordinalName(ma
, libOrdinal
);
421 target
.symbolName
= symbolName
;
422 target
.addend
= addend
;
423 target
.weakImport
= weakImport
;
424 targets
.push_back(target
);
426 if ( diag
.hasError() )
429 uint64_t baseAddress
= ma
->preferredLoadAddress();
431 printf(" segment section address type (dvrsty addr key) target\n");
432 SectionFinder
namer(ma
);
433 ma
->withChainStarts(diag
, 0, ^(const dyld_chained_starts_in_image
* starts
) {
434 ma
->forEachFixupInAllChains(diag
, starts
, false, ^(dyld3
::MachOLoaded
::ChainedFixupPointerOnDisk
* fixupLoc
, const dyld_chained_starts_in_segment
* segInfo
, bool& stop
) {
435 uint64_t vmOffset
= (uint8_t*)fixupLoc
- (uint8_t*)ma
;
436 switch (segInfo
->pointer_format
) {
437 case DYLD_CHAINED_PTR_ARM64E
:
438 if ( fixupLoc
->arm64e
.authRebase
.auth
) {
439 if ( fixupLoc
->arm64e
.authBind
.bind
) {
440 const FixupTarget
& bindTarget
= targets
[fixupLoc
->arm64e
.authBind
.ordinal
];
441 const char* weakImportString
= bindTarget
.weakImport ?
" [weak-import]" : "";
442 if ( bindTarget
.addend
)
443 printf(" %-12s %-16s 0x%08llX %16s (0x%04X %d %s) %s/%s + 0x%llX%s\n",
444 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(), "bind authptr",
445 fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authBind
.addrDiv
,
446 fixupLoc
->arm64e
.keyName(), bindTarget
.dylib
, bindTarget
.symbolName
, bindTarget
.addend
, weakImportString
);
448 printf(" %-12s %-16s 0x%08llX %16s (0x%04X %d %s) %s/%s%s\n",
449 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(), "bind authptr",
450 fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authBind
.addrDiv
,
451 fixupLoc
->arm64e
.keyName(), bindTarget
.dylib
, bindTarget
.symbolName
, weakImportString
);
454 uint64_t targetAddr
= fixupLoc
->arm64e
.authRebase
.target
+ baseAddress
;
455 printf(" %-12s %-16s 0x%08llX %16s (0x%04X %d %s) 0x%08llX\n",
456 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(), "rebase authptr",
457 fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authBind
.addrDiv
,
458 fixupLoc
->arm64e
.keyName(), targetAddr
);
462 if ( fixupLoc
->arm64e
.rebase
.bind
) {
463 const FixupTarget
& bindTarget
= targets
[fixupLoc
->arm64e
.bind
.ordinal
];
464 uint64_t fullAddend
= bindTarget
.addend
+ fixupLoc
->arm64e
.signExtendedAddend();
465 const char* weakImportString
= bindTarget
.weakImport ?
" [weak-import]" : "";
467 printf(" %-12s %-16s 0x%08llX %16s %s/%s + 0x%llX%s\n",
468 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
469 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, fullAddend
, weakImportString
);
471 printf(" %-12s %-16s 0x%08llX %16s %s/%s%s\n",
472 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
473 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, weakImportString
);
476 uint64_t targetAddr
= fixupLoc
->arm64e
.unpackTarget();
477 printf(" %-12s %-16s 0x%08llX %16s 0x%08llX\n",
478 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
479 "rebase pointer", targetAddr
);
483 case DYLD_CHAINED_PTR_ARM64E_OFFSET
:
484 if ( fixupLoc
->arm64e
.authRebase
.auth
) {
485 if ( fixupLoc
->arm64e
.authBind
.bind
) {
486 const FixupTarget
& bindTarget
= targets
[fixupLoc
->arm64e
.authBind
.ordinal
];
487 const char* weakImportString
= bindTarget
.weakImport ?
" [weak-import]" : "";
488 if ( bindTarget
.addend
)
489 printf(" %-12s %-16s 0x%08llX %16s (0x%04X %d %s) %s/%s + 0x%llX%s\n",
490 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(), "bind authptr",
491 fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authBind
.addrDiv
,
492 fixupLoc
->arm64e
.keyName(), bindTarget
.dylib
, bindTarget
.symbolName
, bindTarget
.addend
, weakImportString
);
494 printf(" %-12s %-16s 0x%08llX %16s (0x%04X %d %s) %s/%s%s\n",
495 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(), "bind authptr",
496 fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authBind
.addrDiv
,
497 fixupLoc
->arm64e
.keyName(), bindTarget
.dylib
, bindTarget
.symbolName
, weakImportString
);
500 uint64_t targetAddr
= fixupLoc
->arm64e
.authRebase
.target
+ baseAddress
;
501 printf(" %-12s %-16s 0x%08llX %16s (0x%04X %d %s) 0x%08llX\n",
502 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(), "rebase authptr",
503 fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authBind
.addrDiv
,
504 fixupLoc
->arm64e
.keyName(), targetAddr
);
508 if ( fixupLoc
->arm64e
.rebase
.bind
) {
509 const FixupTarget
& bindTarget
= targets
[fixupLoc
->arm64e
.bind
.ordinal
];
510 uint64_t fullAddend
= bindTarget
.addend
+ fixupLoc
->arm64e
.signExtendedAddend();
511 const char* weakImportString
= bindTarget
.weakImport ?
" [weak-import]" : "";
513 printf(" %-12s %-16s 0x%08llX %16s %s/%s + 0x%llX%s\n",
514 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
515 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, fullAddend
, weakImportString
);
517 printf(" %-12s %-16s 0x%08llX %16s %s/%s%s\n",
518 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
519 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, weakImportString
);
522 uint64_t targetAddr
= fixupLoc
->arm64e
.unpackTarget() + baseAddress
;
523 printf(" %-12s %-16s 0x%08llX %16s 0x%08llX\n",
524 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
525 "rebase pointer", targetAddr
);
529 case DYLD_CHAINED_PTR_64
:
530 if ( fixupLoc
->generic64
.rebase
.bind
) {
531 const FixupTarget
& bindTarget
= targets
[fixupLoc
->generic64
.bind
.ordinal
];
532 uint64_t fullAddend
= bindTarget
.addend
+ fixupLoc
->generic64
.signExtendedAddend();
533 const char* weakImportString
= bindTarget
.weakImport ?
" [weak-import]" : "";
535 printf(" %-12s %-16s 0x%08llX %16s %s/%s + 0x%llX%s\n",
536 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
537 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, fullAddend
, weakImportString
);
539 printf(" %-12s %-16s 0x%08llX %16s %s/%s%s\n",
540 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
541 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, weakImportString
);
544 uint64_t targetAddr
= fixupLoc
->generic64
.unpackedTarget();
545 printf(" %-12s %-16s 0x%08llX %16s 0x%08llX\n",
546 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
547 "rebase pointer", targetAddr
);
550 case DYLD_CHAINED_PTR_64_OFFSET
:
551 if ( fixupLoc
->generic64
.rebase
.bind
) {
552 const FixupTarget
& bindTarget
= targets
[fixupLoc
->generic64
.bind
.ordinal
];
553 uint64_t fullAddend
= bindTarget
.addend
+ fixupLoc
->generic64
.signExtendedAddend();
554 const char* weakImportString
= bindTarget
.weakImport ?
" [weak-import]" : "";
556 printf(" %-12s %-16s 0x%08llX %16s %s/%s + 0x%llX%s\n",
557 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
558 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, fullAddend
, weakImportString
);
560 printf(" %-12s %-16s 0x%08llX %16s %s/%s%s\n",
561 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
562 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, weakImportString
);
565 uint64_t targetAddr
= fixupLoc
->generic64
.unpackedTarget() + baseAddress
;
566 printf(" %-12s %-16s 0x%08llX %16s 0x%08llX\n",
567 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
568 "rebase pointer", targetAddr
);
571 case DYLD_CHAINED_PTR_32
:
572 if ( fixupLoc
->generic32
.rebase
.bind
) {
573 const FixupTarget
& bindTarget
= targets
[fixupLoc
->generic32
.bind
.ordinal
];
574 uint32_t fullAddend
= (uint32_t)bindTarget
.addend
+ fixupLoc
->generic32
.bind
.addend
;
575 const char* weakImportString
= bindTarget
.weakImport ?
" [weak-import]" : "";
577 printf(" %-12s %-16s 0x%08llX %16s %s/%s + 0x%X%s\n",
578 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
579 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, fullAddend
, weakImportString
);
581 printf(" %-12s %-16s 0x%08llX %16s %s/%s%s\n",
582 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
583 "bind pointer", bindTarget
.dylib
, bindTarget
.symbolName
, weakImportString
);
586 uint32_t targetAddr
= fixupLoc
->generic32
.rebase
.target
;
587 printf(" %-12s %-16s 0x%08llX %16s 0x%08X\n",
588 namer
.segmentName(vmOffset
), namer
.sectionName(vmOffset
), vmOffset
+namer
.baseAddress(),
589 "rebase pointer", targetAddr
);
593 fprintf(stderr
, "unknown pointer type %d\n", segInfo
->pointer_format
);
598 if ( diag
.hasError() )
599 fprintf(stderr
, "dyldinfo: %s\n", diag
.errorMessage());
602 static void printOpcodeFixups(const dyld3
::MachOAnalyzer
* ma
)
605 __block std
::vector
<FixupInfo
> fixups
;
606 SectionFinder
namer(ma
);
607 ma
->forEachRebase(diag
, ^(const char* opcodeName
, const dyld3
::MachOLoaded
::LinkEditInfo
& leInfo
, const dyld3
::MachOFile
::SegmentInfo segments
[],
608 bool segIndexSet
, uint32_t pointerSize
, uint8_t segIndex
, uint64_t segOffset
, uint8_t type
, bool& stop
) {
609 const dyld3
::MachOFile
::SegmentInfo
& segment
= segments
[segIndex
];
610 uint64_t locVmAddr
= segment
.vmAddr
+ segOffset
;
611 uint64_t runtimeOffset
= locVmAddr
- namer
.baseAddress();
612 const uint8_t* loc
= ((uint8_t*)ma
+ runtimeOffset
);
613 uint64_t value
= (pointerSize
== 8) ?
*((uint64_t*)(loc
)) : *((uint32_t*)(loc
));
615 fixup
.segName
= namer
.segmentName(runtimeOffset
);
616 fixup
.sectName
= namer
.sectionName(runtimeOffset
);
617 fixup
.address
= locVmAddr
;
618 fixup
.type
= rebaseTypeName(type
);
619 fixup
.targetValue
= value
;
620 fixup
.targetDylib
= nullptr;
621 fixup
.targetSymbolName
= nullptr;
622 fixup
.targetAddend
= 0;
623 fixup
.targetWeakImport
= false;
624 fixups
.push_back(fixup
);
627 ma
->forEachBind(diag
, ^(const char* opcodeName
, const dyld3
::MachOLoaded
::LinkEditInfo
& leInfo
, const dyld3
::MachOFile
::SegmentInfo segments
[],
628 bool segIndexSet
, bool libraryOrdinalSet
, uint32_t dylibCount
, int libOrdinal
,
629 uint32_t pointerSize
, uint8_t segIndex
, uint64_t segOffset
,
630 uint8_t type
, const char* symbolName
, bool weakImport
, bool lazyBind
, uint64_t addend
, bool& stop
) {
631 const dyld3
::MachOFile
::SegmentInfo
& segment
= segments
[segIndex
];
632 uint64_t locVmAddr
= segment
.vmAddr
+ segOffset
;
633 uint64_t runtimeOffset
= locVmAddr
- namer
.baseAddress();
635 fixup
.segName
= namer
.segmentName(runtimeOffset
);
636 fixup
.sectName
= namer
.sectionName(runtimeOffset
);
637 fixup
.address
= locVmAddr
;
638 fixup
.type
= bindTypeName(type
);
639 fixup
.targetValue
= 0;
640 fixup
.targetDylib
= ordinalName(ma
, libOrdinal
);
641 fixup
.targetSymbolName
= symbolName
;
642 fixup
.targetAddend
= addend
;
643 fixup
.targetWeakImport
= weakImport
;
644 fixups
.push_back(fixup
);
645 },^(const char* symbolName
) {
649 std
::sort(fixups
.begin(), fixups
.end(), [](const FixupInfo
& l
, const FixupInfo
& r
) {
652 if ( l
.address
== r
.address
)
653 return (l
.targetSymbolName
== nullptr);
654 return ( l
.address
< r
.address
);
657 printf(" segment section address type target\n");
658 for (const FixupInfo
& fixup
: fixups
) {
659 if ( fixup
.targetSymbolName
== nullptr )
660 printf(" %-12s %-16s 0x%08llX %16s 0x%08llX\n", fixup
.segName
, fixup
.sectName
.c_str(), fixup
.address
, fixup
.type
, fixup
.targetValue
);
661 else if ( fixup
.targetAddend
!= 0 )
662 printf(" %-12s %-16s 0x%08llX %16s %s/%s + 0x%llX\n", fixup
.segName
, fixup
.sectName
.c_str(), fixup
.address
, fixup
.type
, fixup
.targetDylib
, fixup
.targetSymbolName
, fixup
.targetAddend
);
663 else if ( fixup
.targetWeakImport
)
664 printf(" %-12s %-16s 0x%08llX %16s %s/%s [weak-import]\n", fixup
.segName
, fixup
.sectName
.c_str(), fixup
.address
, fixup
.type
, fixup
.targetDylib
, fixup
.targetSymbolName
);
666 printf(" %-12s %-16s 0x%08llX %16s %s/%s\n", fixup
.segName
, fixup
.sectName
.c_str(), fixup
.address
, fixup
.type
, fixup
.targetDylib
, fixup
.targetSymbolName
);
672 static inline std
::string
decimal(int64_t value
) {
674 sprintf(buff
, "%lld", value
);
678 static std
::string
rebaseTargetString(const dyld3
::MachOAnalyzer
* ma
, uint64_t vmAddr
)
680 uint64_t targetLoadAddr
= (uint64_t)ma
+vmAddr
;
681 const char* targetSymbolName
;
682 uint64_t targetSymbolLoadAddr
;
683 if ( ma
->findClosestSymbol(targetLoadAddr
, &targetSymbolName
, &targetSymbolLoadAddr
) ) {
684 uint64_t delta
= targetLoadAddr
- targetSymbolLoadAddr
;
686 return targetSymbolName
;
689 return std
::string(targetSymbolName
) + std
::string("+") + decimal(delta
);
693 __block std
::string result
;
694 ma
->forEachSection(^(const dyld3
::MachOAnalyzer
::SectionInfo
& sectInfo
, bool malformedSectionRange
, bool& stop
) {
695 if ( (sectInfo
.sectAddr
<= vmAddr
) && (vmAddr
< sectInfo
.sectAddr
+sectInfo
.sectSize
) ) {
696 if ( (sectInfo
.sectFlags
& SECTION_TYPE
) == S_CSTRING_LITERALS
) {
697 const char* cstring
= (char*)ma
+ (vmAddr
-ma
->preferredLoadAddress());
698 result
= std
::string("\"") + cstring
+ std
::string("\"");
701 result
= std
::string(sectInfo
.segInfo
.segName
) + "/" + sectInfo
.sectName
+ "+" + decimal(vmAddr
- sectInfo
.sectAddr
);
709 static void printSymbolicChainedFixups(const dyld3
::MachOAnalyzer
* ma
)
711 // build array of targets
712 __block Diagnostics diag
;
713 __block std
::vector
<FixupTarget
> targets
;
714 ma
->forEachChainedFixupTarget(diag
, ^(int libOrdinal
, const char* symbolName
, uint64_t addend
, bool weakImport
, bool& stop
) {
717 target
.dylib
= ordinalName(ma
, libOrdinal
);
718 target
.symbolName
= symbolName
;
719 target
.addend
= addend
;
720 target
.weakImport
= weakImport
;
721 targets
.push_back(target
);
723 if ( diag
.hasError() )
726 // walk all fixup chains
727 uint64_t baseAddress
= ma
->preferredLoadAddress();
728 SectionFinder
sectionInfo(ma
);
729 __block
uint64_t lastSymbolVmOffset
= 0;
730 __block
bool lastSymbolIsSectionStart
= false;
731 ma
->withChainStarts(diag
, 0, ^(const dyld_chained_starts_in_image
* starts
) {
732 ma
->forEachFixupInAllChains(diag
, starts
, false, ^(dyld3
::MachOLoaded
::ChainedFixupPointerOnDisk
* fixupLoc
, const dyld_chained_starts_in_segment
* segInfo
, bool& stop
) {
733 uint64_t fixupVmOffset
= (uint8_t*)fixupLoc
- (uint8_t*)ma
;
734 if ( sectionInfo
.isNewSection(fixupVmOffset
) ) {
735 printf(" 0x%08llX %-12s %-16s \n", sectionInfo
.currentSectionAddress(), sectionInfo
.segmentName(fixupVmOffset
), sectionInfo
.sectionName(fixupVmOffset
));
736 lastSymbolVmOffset
= sectionInfo
.currentSectionAddress()-sectionInfo
.baseAddress();
737 lastSymbolIsSectionStart
= true;
739 const char* symbolName
;
740 uint64_t symbolLoadAddr
= 0;
741 if ( ma
->findClosestSymbol((uint64_t)fixupLoc
, &symbolName
, &symbolLoadAddr
) ) {
742 uint64_t symbolVmOffset
= symbolLoadAddr
- (uint64_t)ma
;
743 if ( (symbolVmOffset
!= lastSymbolVmOffset
) || lastSymbolIsSectionStart
) {
744 printf(" %s:\n", symbolName
);
745 lastSymbolVmOffset
= symbolVmOffset
;
746 lastSymbolIsSectionStart
= false;
749 const char* fixupKind
= "";
750 std
::string fixupTarget
;
752 switch (segInfo
->pointer_format
) {
753 case DYLD_CHAINED_PTR_ARM64E
:
754 if ( fixupLoc
->arm64e
.authRebase
.auth
) {
755 sprintf(authInfo
, "(0x%04X %d %s)", fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authBind
.addrDiv
, fixupLoc
->arm64e
.keyName());
756 if ( fixupLoc
->arm64e
.authBind
.bind
) {
757 const FixupTarget
& bindTarget
= targets
[fixupLoc
->arm64e
.authBind
.ordinal
];
758 fixupKind
= "bind authptr";
759 fixupTarget
= std
::string(bindTarget
.dylib
) + "/" + bindTarget
.symbolName
;
760 if ( bindTarget
.addend
)
761 fixupTarget
+= std
::string("+") + decimal(bindTarget
.addend
);
762 if ( bindTarget
.weakImport
)
763 fixupTarget
+= " [weak-import]";
766 uint64_t targetVmAddr
= fixupLoc
->arm64e
.authRebase
.target
+ baseAddress
;
767 fixupKind
= "rebase authptr";
768 fixupTarget
= rebaseTargetString(ma
, targetVmAddr
);
773 if ( fixupLoc
->arm64e
.rebase
.bind
) {
774 const FixupTarget
& bindTarget
= targets
[fixupLoc
->arm64e
.bind
.ordinal
];
775 uint64_t fullAddend
= bindTarget
.addend
+ fixupLoc
->arm64e
.signExtendedAddend();
776 fixupKind
= "bind pointer";
777 fixupTarget
= std
::string(bindTarget
.dylib
) + "/" + bindTarget
.symbolName
;
779 fixupTarget
+= std
::string("+") + decimal(fullAddend
);
780 if ( bindTarget
.weakImport
)
781 fixupTarget
+= " [weak-import]";
784 uint64_t targetVmAddr
= fixupLoc
->arm64e
.unpackTarget();
785 fixupKind
= "rebase pointer";
786 fixupTarget
= rebaseTargetString(ma
, targetVmAddr
);
789 printf(" +0x%04llX %16s %30s %s\n", fixupVmOffset
-lastSymbolVmOffset
, fixupKind
, authInfo
, fixupTarget
.c_str());
791 case DYLD_CHAINED_PTR_ARM64E_OFFSET
:
792 if ( fixupLoc
->arm64e
.authRebase
.auth
) {
793 sprintf(authInfo
, "(0x%04X %d %s)", fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authBind
.addrDiv
, fixupLoc
->arm64e
.keyName());
794 if ( fixupLoc
->arm64e
.authBind
.bind
) {
795 const FixupTarget
& bindTarget
= targets
[fixupLoc
->arm64e
.authBind
.ordinal
];
796 fixupKind
= "bind authptr";
797 fixupTarget
= std
::string(bindTarget
.dylib
) + "/" + bindTarget
.symbolName
;
798 if ( bindTarget
.addend
)
799 fixupTarget
+= std
::string("+") + decimal(bindTarget
.addend
);
800 if ( bindTarget
.weakImport
)
801 fixupTarget
+= " [weak-import]";
804 uint64_t targetVmAddr
= fixupLoc
->arm64e
.authRebase
.target
+ baseAddress
;
805 fixupKind
= "rebase authptr";
806 fixupTarget
= rebaseTargetString(ma
, targetVmAddr
);
811 if ( fixupLoc
->arm64e
.rebase
.bind
) {
812 const FixupTarget
& bindTarget
= targets
[fixupLoc
->arm64e
.bind
.ordinal
];
813 uint64_t fullAddend
= bindTarget
.addend
+ fixupLoc
->arm64e
.signExtendedAddend();
814 fixupKind
= "bind pointer";
815 fixupTarget
= std
::string(bindTarget
.dylib
) + "/" + bindTarget
.symbolName
;
817 fixupTarget
+= std
::string("+") + decimal(fullAddend
);
818 if ( bindTarget
.weakImport
)
819 fixupTarget
+= " [weak-import]";
822 uint64_t targetVmAddr
= fixupLoc
->arm64e
.unpackTarget() + baseAddress
;
823 fixupKind
= "rebase pointer";
824 fixupTarget
= rebaseTargetString(ma
, targetVmAddr
);
827 printf(" +0x%04llX %16s %30s %s\n", fixupVmOffset
-lastSymbolVmOffset
, fixupKind
, authInfo
, fixupTarget
.c_str());
829 case DYLD_CHAINED_PTR_64
:
830 if ( fixupLoc
->generic64
.rebase
.bind
) {
831 const FixupTarget
& bindTarget
= targets
[fixupLoc
->generic64
.bind
.ordinal
];
832 fixupKind
= "bind pointer";
833 uint64_t fullAddend
= bindTarget
.addend
+ fixupLoc
->generic64
.signExtendedAddend();
834 fixupTarget
= std
::string(bindTarget
.dylib
) + "/" + bindTarget
.symbolName
;
836 fixupTarget
+= std
::string("+") + decimal(fullAddend
);
837 if ( bindTarget
.weakImport
)
838 fixupTarget
+= " [weak-import]";
841 uint64_t targetVmAddr
= fixupLoc
->generic64
.unpackedTarget();
842 fixupKind
= "rebase pointer";
843 fixupTarget
= rebaseTargetString(ma
, targetVmAddr
);
845 printf(" +0x%04llX %16s %s\n", fixupVmOffset
-lastSymbolVmOffset
, fixupKind
, fixupTarget
.c_str());
847 case DYLD_CHAINED_PTR_64_OFFSET
:
848 if ( fixupLoc
->generic64
.rebase
.bind
) {
849 const FixupTarget
& bindTarget
= targets
[fixupLoc
->generic64
.bind
.ordinal
];
850 fixupKind
= "bind pointer";
851 uint64_t fullAddend
= bindTarget
.addend
+ fixupLoc
->generic64
.signExtendedAddend();
852 fixupTarget
= std
::string(bindTarget
.dylib
) + "/" + bindTarget
.symbolName
;
854 fixupTarget
+= std
::string("+") + decimal(fullAddend
);
855 if ( bindTarget
.weakImport
)
856 fixupTarget
+= " [weak-import]";
859 uint64_t targetVmAddr
= fixupLoc
->generic64
.unpackedTarget() + baseAddress
;
860 fixupKind
= "rebase pointer";
861 fixupTarget
= rebaseTargetString(ma
, targetVmAddr
);
863 printf(" +0x%04llX %16s %s\n", fixupVmOffset
-lastSymbolVmOffset
, fixupKind
, fixupTarget
.c_str());
865 case DYLD_CHAINED_PTR_32
:
866 if ( fixupLoc
->generic32
.rebase
.bind
) {
867 const FixupTarget
& bindTarget
= targets
[fixupLoc
->generic32
.bind
.ordinal
];
868 uint32_t fullAddend
= (uint32_t)bindTarget
.addend
+ fixupLoc
->generic32
.bind
.addend
;
869 fixupKind
= "bind pointer";
870 fixupTarget
= std
::string(bindTarget
.dylib
) + "/" + bindTarget
.symbolName
;
872 fixupTarget
+= std
::string("+") + decimal(fullAddend
);
873 if ( bindTarget
.weakImport
)
874 fixupTarget
+= " [weak-import]";
877 uint32_t targetAddr
= fixupLoc
->generic32
.rebase
.target
;
878 fixupKind
= "rebase pointer";
879 fixupTarget
= rebaseTargetString(ma
, targetAddr
);
881 printf(" +0x%04llX %16s %s\n", fixupVmOffset
-lastSymbolVmOffset
, fixupKind
, fixupTarget
.c_str());
884 fprintf(stderr
, "unknown pointer type %d\n", segInfo
->pointer_format
);
889 if ( diag
.hasError() )
890 fprintf(stderr
, "dyldinfo: %s\n", diag
.errorMessage());
893 struct SymbolicFixupInfo
900 static void printSymbolicOpcodeFixups(const dyld3
::MachOAnalyzer
* ma
)
903 __block std
::vector
<SymbolicFixupInfo
> fixups
;
904 SectionFinder
namer(ma
);
905 ma
->forEachRebase(diag
, ^(const char* opcodeName
, const dyld3
::MachOLoaded
::LinkEditInfo
& leInfo
, const dyld3
::MachOFile
::SegmentInfo segments
[],
906 bool segIndexSet
, uint32_t pointerSize
, uint8_t segIndex
, uint64_t segOffset
, uint8_t type
, bool& stop
) {
907 const dyld3
::MachOFile
::SegmentInfo
& segment
= segments
[segIndex
];
908 uint64_t locVmAddr
= segment
.vmAddr
+ segOffset
;
909 uint64_t runtimeOffset
= locVmAddr
- namer
.baseAddress();
910 const uint8_t* loc
= ((uint8_t*)ma
+ runtimeOffset
);
911 uint64_t value
= (pointerSize
== 8) ?
*((uint64_t*)(loc
)) : *((uint32_t*)(loc
));
912 SymbolicFixupInfo fixup
;
913 fixup
.address
= locVmAddr
;
914 fixup
.kind
= rebaseTypeName(type
);
915 fixup
.target
= rebaseTargetString(ma
, value
);
916 fixups
.push_back(fixup
);
919 ma
->forEachBind(diag
, ^(const char* opcodeName
, const dyld3
::MachOLoaded
::LinkEditInfo
& leInfo
, const dyld3
::MachOFile
::SegmentInfo segments
[],
920 bool segIndexSet
, bool libraryOrdinalSet
, uint32_t dylibCount
, int libOrdinal
,
921 uint32_t pointerSize
, uint8_t segIndex
, uint64_t segOffset
,
922 uint8_t type
, const char* symbolName
, bool weakImport
, bool lazyBind
, uint64_t addend
, bool& stop
) {
923 const dyld3
::MachOFile
::SegmentInfo
& segment
= segments
[segIndex
];
924 uint64_t locVmAddr
= segment
.vmAddr
+ segOffset
;
925 SymbolicFixupInfo fixup
;
926 fixup
.address
= locVmAddr
;
927 fixup
.kind
= bindTypeName(type
);
928 fixup
.target
= std
::string(ordinalName(ma
, libOrdinal
)) + "/" + symbolName
;
930 fixup
.target
+= std
::string("+") + decimal(addend
);
932 fixup
.target
+= " [weak-import]";
933 fixups
.push_back(fixup
);
934 },^(const char* symbolName
) {
938 std
::sort(fixups
.begin(), fixups
.end(), [](const SymbolicFixupInfo
& l
, const SymbolicFixupInfo
& r
) {
941 return ( l
.address
< r
.address
);
944 SectionFinder
sectionTracker(ma
);
945 uint64_t lastSymbolVmOffset
= 0;
946 for (const SymbolicFixupInfo
& fixup
: fixups
) {
947 uint64_t vmOffset
= fixup
.address
;
948 uint64_t vmAddr
= sectionTracker
.baseAddress() + vmOffset
;
949 if ( sectionTracker
.isNewSection(vmOffset
) ) {
950 printf(" 0x%08llX %-12s %-16s \n", vmAddr
, sectionTracker
.segmentName(vmOffset
), sectionTracker
.sectionName(vmOffset
));
951 lastSymbolVmOffset
= vmOffset
;
953 const char* symbolName
;
954 uint64_t symbolLoadAddr
= 0;
955 if ( ma
->findClosestSymbol((uint64_t)ma
+vmOffset
, &symbolName
, &symbolLoadAddr
) ) {
956 uint64_t symbolVmOffset
= symbolLoadAddr
- (uint64_t)ma
;
957 if ( symbolVmOffset
!= lastSymbolVmOffset
) {
958 printf(" %s:\n", symbolName
);
959 lastSymbolVmOffset
= symbolVmOffset
;
962 printf(" +0x%04llX %16s %s\n", vmOffset
- lastSymbolVmOffset
, fixup
.kind
, fixup
.target
.c_str());
966 static void printFixups(const dyld3
::MachOAnalyzer
* ma
)
968 printf(" -fixups:\n");
969 if ( ma
->isPreload() || (ma
->isStaticExecutable() && !ma
->hasChainedFixups()) ) {
970 printPreloadChainedFixups(ma
);
972 else if ( ma
->hasChainedFixups() ) {
973 printChainedFixups(ma
);
976 printOpcodeFixups(ma
);
981 static void printSymbolicFixups(const dyld3
::MachOAnalyzer
* ma
)
983 printf(" -symbolic_fixups:\n");
984 if ( ma
->isPreload() || ma
->isStaticExecutable() ) {
985 printPreloadChainedFixups(ma
);
987 else if ( ma
->hasChainedFixups() ) {
988 printSymbolicChainedFixups(ma
);
991 printSymbolicOpcodeFixups(ma
);
997 static void printExports(const dyld3
::MachOAnalyzer
* ma
)
999 printf(" -exports:\n");
1000 printf(" offset symbol\n");
1002 ma
->forEachExportedSymbol(diag
, ^(const char* symbolName
, uint64_t imageOffset
, uint64_t flags
, uint64_t other
, const char* importName
, bool& stop
) {
1003 //printf("0x%08llX %s\n", imageOffset, symbolName);
1004 const bool reExport
= (flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
);
1005 const bool weakDef
= (flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
);
1006 const bool resolver
= (flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
);
1007 const bool threadLocal
= ((flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
);
1008 const bool abs
= ((flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
);
1010 printf(" [re-export] ");
1012 printf(" 0x%08llX ", imageOffset
);
1013 printf("%s", symbolName
);
1014 if ( weakDef
|| threadLocal
|| resolver
|| abs
) {
1015 bool needComma
= false;
1021 if ( threadLocal
) {
1024 printf("per-thread");
1036 printf("resolver=0x%08llX", other
);
1042 if ( importName
[0] == '\0' )
1043 printf(" (from %s)", ordinalName(ma
, (int)other
));
1045 printf(" (%s from %s)", importName
, ordinalName(ma
, (int)other
));
1052 static void printObjC(const dyld3
::MachOAnalyzer
* ma
)
1055 const bool contentRebased
= false;
1056 const uint32_t pointerSize
= ma
->pointerSize();
1058 auto printMethod
= ^(uint64_t methodVMAddr
, const dyld3
::MachOAnalyzer
::ObjCMethod
& method
) {
1059 const char* type
= "method";
1060 dyld3
::MachOAnalyzer
::PrintableStringResult methodNameResult
;
1061 const char* methodName
= ma
->getPrintableString(method
.nameVMAddr
, methodNameResult
);
1062 switch (methodNameResult
) {
1063 case dyld3
::MachOAnalyzer
::PrintableStringResult
::CanPrint
:
1064 // The string is already valid
1066 case dyld3
::MachOAnalyzer
::PrintableStringResult
::FairPlayEncrypted
:
1067 methodName
= "### fairplay encrypted";
1069 case dyld3
::MachOAnalyzer
::PrintableStringResult
::ProtectedSection
:
1070 methodName
= "### protected section";
1072 case dyld3
::MachOAnalyzer
::PrintableStringResult
::UnknownSection
:
1073 methodName
= "### unknown section";
1076 printf(" %10s 0x%08llX %s\n",
1077 type
, methodVMAddr
, methodName
);
1080 printf(" -objc:\n");
1081 printf(" type vmaddr data-vmaddr name\n");
1082 auto printClass
= ^(Diagnostics
& diag
, uint64_t classVMAddr
,
1083 uint64_t classSuperclassVMAddr
, uint64_t classDataVMAddr
,
1084 const dyld3
::MachOAnalyzer
::ObjCClassInfo
& objcClass
, bool isMetaClass
) {
1085 const char* type
= "class";
1087 type
= "meta-class";
1088 dyld3
::MachOAnalyzer
::PrintableStringResult classNameResult
;
1089 const char* className
= ma
->getPrintableString(objcClass
.nameVMAddr(pointerSize
), classNameResult
);
1090 switch (classNameResult
) {
1091 case dyld3
::MachOAnalyzer
::PrintableStringResult
::CanPrint
:
1092 // The string is already valid
1094 case dyld3
::MachOAnalyzer
::PrintableStringResult
::FairPlayEncrypted
:
1095 className
= "### fairplay encrypted";
1097 case dyld3
::MachOAnalyzer
::PrintableStringResult
::ProtectedSection
:
1098 className
= "### protected section";
1100 case dyld3
::MachOAnalyzer
::PrintableStringResult
::UnknownSection
:
1101 className
= "### unknown section";
1104 printf(" %10s 0x%08llX 0x%08llX %s\n",
1105 type
, classVMAddr
, objcClass
.dataVMAddr
, className
);
1107 // Now print the methods on this class
1108 ma
->forEachObjCMethod(objcClass
.baseMethodsVMAddr(pointerSize
), contentRebased
,
1111 auto printCategory
= ^(Diagnostics
& diag
, uint64_t categoryVMAddr
,
1112 const dyld3
::MachOAnalyzer
::ObjCCategory
& objcCategory
) {
1113 const char* type
= "category";
1114 dyld3
::MachOAnalyzer
::PrintableStringResult categoryNameResult
;
1115 const char* categoryName
= ma
->getPrintableString(objcCategory
.nameVMAddr
, categoryNameResult
);
1116 switch (categoryNameResult
) {
1117 case dyld3
::MachOAnalyzer
::PrintableStringResult
::CanPrint
:
1118 // The string is already valid
1120 case dyld3
::MachOAnalyzer
::PrintableStringResult
::FairPlayEncrypted
:
1121 categoryName
= "### fairplay encrypted";
1123 case dyld3
::MachOAnalyzer
::PrintableStringResult
::ProtectedSection
:
1124 categoryName
= "### protected section";
1126 case dyld3
::MachOAnalyzer
::PrintableStringResult
::UnknownSection
:
1127 categoryName
= "### unknown section";
1130 printf(" %10s 0x%08llX %s\n",
1131 type
, categoryVMAddr
, categoryName
);
1133 // Now print the methods on this category
1134 ma
->forEachObjCMethod(objcCategory
.instanceMethodsVMAddr
, contentRebased
,
1136 ma
->forEachObjCMethod(objcCategory
.classMethodsVMAddr
, contentRebased
,
1139 auto printProtocol
= ^(Diagnostics
& diag
, uint64_t protocolVMAddr
,
1140 const dyld3
::MachOAnalyzer
::ObjCProtocol
& objCProtocol
) {
1141 const char* type
= "protocol";
1142 dyld3
::MachOAnalyzer
::PrintableStringResult protocolNameResult
;
1143 const char* protocolName
= ma
->getPrintableString(objCProtocol
.nameVMAddr
, protocolNameResult
);
1144 switch (protocolNameResult
) {
1145 case dyld3
::MachOAnalyzer
::PrintableStringResult
::CanPrint
:
1146 // The string is already valid
1148 case dyld3
::MachOAnalyzer
::PrintableStringResult
::FairPlayEncrypted
:
1149 protocolName
= "### fairplay encrypted";
1151 case dyld3
::MachOAnalyzer
::PrintableStringResult
::ProtectedSection
:
1152 protocolName
= "### protected section";
1154 case dyld3
::MachOAnalyzer
::PrintableStringResult
::UnknownSection
:
1155 protocolName
= "### unknown section";
1158 printf(" %10s 0x%08llX %s\n",
1159 type
, protocolVMAddr
, protocolName
);
1161 // Now print the methods on this protocol
1162 ma
->forEachObjCMethod(objCProtocol
.instanceMethodsVMAddr
, contentRebased
,
1164 ma
->forEachObjCMethod(objCProtocol
.classMethodsVMAddr
, contentRebased
,
1166 ma
->forEachObjCMethod(objCProtocol
.optionalInstanceMethodsVMAddr
, contentRebased
,
1168 ma
->forEachObjCMethod(objCProtocol
.optionalClassMethodsVMAddr
, contentRebased
,
1171 ma
->forEachObjCClass(diag
, contentRebased
, printClass
);
1172 ma
->forEachObjCCategory(diag
, contentRebased
, printCategory
);
1173 ma
->forEachObjCProtocol(diag
, contentRebased
, printProtocol
);
1178 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>]* <options>* <mach-o file>+\n"
1179 "\t-segments print segments\n"
1180 "\t-dependents print dependent dylibs\n"
1181 "\t-fixups print locations dyld will rebase/bind\n"
1182 "\t-exports print addresses of all symbols this file exports\n"
1183 "\t-objc print objc classes, categories, etc\n"
1187 static bool inStringVector(const std
::vector
<const char*>& vect
, const char* target
)
1189 for (const char* str
: vect
) {
1190 if ( strcmp(str
, target
) == 0 )
1197 int main(int argc
, const char* argv
[])
1204 std
::vector
<const char*> files
;
1205 std
::vector
<const char*> cmdLineArchs
;
1206 for (int i
=1; i
< argc
; ++i
) {
1207 const char* arg
= argv
[i
];
1208 if ( arg
[0] == '-' ) {
1209 if ( strcmp(arg
, "-arch") == 0 ) {
1211 cmdLineArchs
.push_back(argv
[i
]);
1214 fprintf(stderr
, "-arch missing architecture name");
1220 files
.push_back(arg
);
1223 if ( files
.size() == 0 ) {
1228 for (const char* path
: files
) {
1230 dyld3
::closure
::FileSystemPhysical fileSystem
;
1231 dyld3
::closure
::LoadedFileInfo info
;
1232 char realerPath
[MAXPATHLEN
];
1233 __block
bool printedError
= false;
1234 if (!fileSystem
.loadFile(path
, info
, realerPath
, ^(const char* format
, ...) {
1235 fprintf(stderr
, "dyldinfo: ");
1237 va_start(list
, format
);
1238 vfprintf(stderr
, format
, list
);
1240 printedError
= true;
1243 fprintf(stderr
, "dyldinfo: %s: file not found\n", path
);
1246 __block std
::vector
<const char*> archesForFile
;
1247 __block dyld3
::Platform platform
= dyld3
::Platform
::unknown
;
1248 if ( dyld3
::FatFile
::isFatFile(info
.fileContent
) ) {
1249 const dyld3
::FatFile
* ff
= (dyld3
::FatFile
*)info
.fileContent
;
1250 ff
->forEachSlice(diag
, info
.fileContentLen
, ^(uint32_t sliceCpuType
, uint32_t sliceCpuSubType
, const void* sliceStart
, uint64_t sliceSize
, bool& stop
) {
1251 const char* sliceArchName
= dyld3
::MachOFile
::archName(sliceCpuType
, sliceCpuSubType
);
1252 if ( cmdLineArchs
.empty() || inStringVector(cmdLineArchs
, sliceArchName
) ) {
1253 archesForFile
.push_back(sliceArchName
);
1254 const dyld3
::MachOFile
* mf
= (dyld3
::MachOFile
*)sliceStart
;
1255 mf
->forEachSupportedPlatform(^(dyld3
::Platform plat
, uint32_t minOS
, uint32_t sdk
) {
1256 if ( platform
== dyld3
::Platform
::unknown
)
1263 const dyld3
::MachOFile
* mo
= (dyld3
::MachOFile
*)info
.fileContent
;
1264 if ( mo
->isMachO(diag
, info
.sliceLen
) ) {
1265 archesForFile
.push_back(mo
->archName());
1266 mo
->forEachSupportedPlatform(^(dyld3
::Platform plat
, uint32_t minOS
, uint32_t sdk
) {
1267 if ( platform
== dyld3
::Platform
::unknown
)
1272 fprintf(stderr
, "dyldinfo: %s: %s\n", path
, diag
.errorMessage());
1276 if ( archesForFile
.empty() ) {
1277 fprintf(stderr
, "dyldinfo: %s: does not contain specified arch(s)\n", path
);
1280 char loadedPath
[MAXPATHLEN
];
1281 for (const char* sliceArch
: archesForFile
) {
1282 info
= dyld3
::MachOAnalyzer
::load(diag
, fileSystem
, path
, dyld3
::GradedArchs
::forName(sliceArch
), platform
, loadedPath
);
1283 if ( diag
.hasError() ) {
1284 fprintf(stderr
, "dyldinfo: %s\n", diag
.errorMessage());
1287 const dyld3
::MachOAnalyzer
* ma
= (dyld3
::MachOAnalyzer
*)info
.fileContent
;
1288 printf("%s [%s]:\n", path
, sliceArch
);
1290 bool somethingPrinted
= false;
1291 for (int i
=1; i
< argc
; ++i
) {
1292 const char* arg
= argv
[i
];
1293 if ( arg
[0] != '-' )
1295 if ( strcmp(arg
, "-arch") == 0 ) {
1296 // handled previously
1299 else if ( strcmp(arg
, "-platform") == 0 ) {
1301 somethingPrinted
= true;
1303 else if ( strcmp(arg
, "-segments") == 0 ) {
1305 somethingPrinted
= true;
1307 else if ( strcmp(arg
, "-dependents") == 0 ) {
1308 printDependents(ma
);
1309 somethingPrinted
= true;
1311 else if ( strcmp(arg
, "-fixups") == 0 ) {
1313 somethingPrinted
= true;
1315 else if ( strcmp(arg
, "-exports") == 0 ) {
1317 somethingPrinted
= true;
1319 else if ( strcmp(arg
, "-fixup_chains") == 0 ) {
1321 somethingPrinted
= true;
1323 else if ( strcmp(arg
, "-fixup_chain_details") == 0 ) {
1324 printChainDetails(ma
);
1325 somethingPrinted
= true;
1327 else if ( strcmp(arg
, "-symbolic_fixups") == 0 ) {
1328 printSymbolicFixups(ma
);
1329 somethingPrinted
= true;
1331 else if ( strcmp(arg
, "-opcodes") == 0 ) {
1333 else if ( strcmp(arg
, "-shared_region") == 0 ) {
1335 else if ( strcmp(arg
, "-function_starts") == 0 ) {
1337 else if ( strcmp(arg
, "-data_in_code") == 0 ) {
1339 else if ( strcmp(arg
, "-objc") == 0 ) {
1341 somethingPrinted
= true;
1344 fprintf(stderr
, "unknown option: %s\n", arg
);
1348 if ( !somethingPrinted
) {
1351 printDependents(ma
);