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>
33 #include <mach-o/dyld_priv.h>
38 #include <unordered_set>
42 #include "MachOFile.h"
43 #include "MachOLoaded.h"
44 #include "MachOAnalyzer.h"
45 #include "MachOAnalyzerSet.h"
46 #include "ClosureFileSystemPhysical.h"
47 #include "DyldSharedCache.h"
49 typedef dyld3::MachOLoaded::ChainedFixupPointerOnDisk ChainedFixupPointerOnDisk
;
51 static void versionToString(uint32_t value
, char buffer
[32])
54 strcpy(buffer
, "n/a");
55 else if ( value
& 0xFF )
56 sprintf(buffer
, "%d.%d.%d", value
>> 16, (value
>> 8) & 0xFF, value
& 0xFF);
58 sprintf(buffer
, "%d.%d", value
>> 16, (value
>> 8) & 0xFF);
61 static void printPlatforms(const dyld3::MachOAnalyzer
* ma
)
63 printf(" -platform:\n");
64 printf(" platform minOS sdk\n");
65 ma
->forEachSupportedPlatform(^(dyld3::Platform platform
, uint32_t minOS
, uint32_t sdk
) {
68 versionToString(minOS
, osVers
);
69 versionToString(sdk
, sdkVers
);
70 printf(" %15s %-7s %-7s\n", dyld3::MachOFile::platformName(platform
), osVers
, sdkVers
);
74 static void permString(uint32_t permFlags
, char str
[4])
76 str
[0] = (permFlags
& VM_PROT_READ
) ? 'r' : '.';
77 str
[1] = (permFlags
& VM_PROT_WRITE
) ? 'w' : '.';
78 str
[2] = (permFlags
& VM_PROT_EXECUTE
) ? 'x' : '.';
82 static void printSegments(const dyld3::MachOAnalyzer
* ma
)
84 if ( ma
->inDyldCache() ) {
85 printf(" -segments:\n");
86 printf(" load-address segment section sect-size seg-size perm\n");
87 __block
const char* lastSegName
= "";
88 ma
->forEachSection(^(const dyld3::MachOFile::SectionInfo
& sectInfo
, bool malformedSectionRange
, bool& stop
) {
89 if ( strcmp(lastSegName
, sectInfo
.segInfo
.segName
) != 0 ) {
91 permString(sectInfo
.segInfo
.protections
, permChars
);
92 printf(" 0x%08llX %-16s %16lluKB %s\n", sectInfo
.segInfo
.vmAddr
, sectInfo
.segInfo
.segName
, sectInfo
.segInfo
.vmSize
/1024, permChars
);
93 lastSegName
= sectInfo
.segInfo
.segName
;
95 printf(" 0x%08llX %-16s %6llu\n", sectInfo
.sectAddr
, sectInfo
.sectName
, sectInfo
.sectSize
);
99 printf(" -segments:\n");
100 printf(" load-offset segment section sect-size seg-size perm\n");
101 __block
const char* lastSegName
= "";
102 __block
uint64_t firstSegVmAddr
= 0;
103 ma
->forEachSection(^(const dyld3::MachOFile::SectionInfo
& sectInfo
, bool malformedSectionRange
, bool& stop
) {
104 if ( lastSegName
[0] == '\0' )
105 firstSegVmAddr
= sectInfo
.segInfo
.vmAddr
;
106 if ( strcmp(lastSegName
, sectInfo
.segInfo
.segName
) != 0 ) {
108 permString(sectInfo
.segInfo
.protections
, permChars
);
109 printf(" 0x%08llX %-16s %6lluKB %s\n", sectInfo
.segInfo
.vmAddr
- firstSegVmAddr
, sectInfo
.segInfo
.segName
, sectInfo
.segInfo
.vmSize
/1024, permChars
);
110 lastSegName
= sectInfo
.segInfo
.segName
;
112 printf(" 0x%08llX %-16s %6llu\n", sectInfo
.sectAddr
-firstSegVmAddr
, sectInfo
.sectName
, sectInfo
.sectSize
);
118 static void printDependents(const dyld3::MachOAnalyzer
* ma
)
120 printf(" -dependents:\n");
121 printf(" attributes load path\n");
122 ma
->forEachDependentDylib(^(const char* loadPath
, bool isWeak
, bool isReExport
, bool isUpward
, uint32_t compatVersion
, uint32_t curVersion
, bool &stop
) {
123 const char* attribute
= "";
125 attribute
= "weak_import";
126 else if ( isReExport
)
127 attribute
= "re-export";
129 attribute
= "upward";
130 printf(" %-12s %s\n", attribute
, loadPath
);
134 static bool liveMachO(const dyld3::MachOAnalyzer
* ma
, const DyldSharedCache
* dyldCache
, size_t cacheLen
)
136 if ( dyldCache
== nullptr )
138 const uint8_t* cacheStart
= (uint8_t*)dyldCache
;
139 const uint8_t* cacheEnd
= &cacheStart
[cacheLen
];
140 if ( (uint8_t*)ma
< cacheStart
)
142 if ( (uint8_t*)ma
> cacheEnd
)
145 // only return true for live images
146 return ( dyld_image_header_containing_address(ma
) != nullptr );
149 static void printInitializers(const dyld3::MachOAnalyzer
* ma
, const DyldSharedCache
* dyldCache
, size_t cacheLen
)
151 printf(" -inits:\n");
153 const dyld3::MachOAnalyzer::VMAddrConverter vmAddrConverter
= (ma
->inDyldCache() ? dyldCache
->makeVMAddrConverter(true) : ma
->makeVMAddrConverter(false));
154 ma
->forEachInitializer(diag
, vmAddrConverter
, ^(uint32_t offset
) {
155 uint64_t targetLoadAddr
= (uint64_t)ma
+offset
;
156 const char* symbolName
;
157 uint64_t symbolLoadAddr
;
158 if ( ma
->findClosestSymbol(targetLoadAddr
, &symbolName
, &symbolLoadAddr
) ) {
159 uint64_t delta
= targetLoadAddr
- symbolLoadAddr
;
161 printf(" 0x%08X %s\n", offset
, symbolName
);
163 printf(" 0x%08X %s + 0x%llX\n", offset
, symbolName
, delta
);
166 printf(" 0x%08X\n", offset
);
168 if ( ma
->hasPlusLoadMethod(diag
) ) {
169 // can't inspect ObjC of a live dylib
170 if ( liveMachO(ma
, dyldCache
, cacheLen
) ) {
171 printf(" <<<cannot print objc data on live dylib>>>\n");
174 const uint32_t pointerSize
= ma
->pointerSize();
175 uint64_t prefLoadAddress
= ma
->preferredLoadAddress();
176 // print all +load methods on classes in this image
177 ma
->forEachObjCClass(diag
, vmAddrConverter
, ^(Diagnostics
& diag
, uint64_t classVMAddr
,
178 uint64_t classSuperclassVMAddr
, uint64_t classDataVMAddr
,
179 const dyld3::MachOAnalyzer::ObjCClassInfo
& objcClass
, bool isMetaClass
) {
182 dyld3::MachOAnalyzer::PrintableStringResult classNameResult
;
183 const char* className
= ma
->getPrintableString(objcClass
.nameVMAddr(pointerSize
), classNameResult
);
184 if ( classNameResult
== dyld3::MachOAnalyzer::PrintableStringResult::CanPrint
) {
185 ma
->forEachObjCMethod(objcClass
.baseMethodsVMAddr(pointerSize
), vmAddrConverter
, ^(uint64_t methodVMAddr
, const dyld3::MachOAnalyzer::ObjCMethod
& method
) {
186 dyld3::MachOAnalyzer::PrintableStringResult methodNameResult
;
187 const char* methodName
= ma
->getPrintableString(method
.nameVMAddr
, methodNameResult
);
188 if ( methodNameResult
== dyld3::MachOAnalyzer::PrintableStringResult::CanPrint
) {
189 if ( strcmp(methodName
, "load") == 0 )
190 printf(" 0x%08llX +[%s %s]\n", methodVMAddr
-prefLoadAddress
, className
, methodName
);
195 // print all +load methods on categories in this image
196 ma
->forEachObjCCategory(diag
, vmAddrConverter
, ^(Diagnostics
& diag
, uint64_t categoryVMAddr
,
197 const dyld3::MachOAnalyzer::ObjCCategory
& objcCategory
) {
198 dyld3::MachOAnalyzer::PrintableStringResult categoryNameResult
;
199 const char* categoryName
= ma
->getPrintableString(objcCategory
.nameVMAddr
, categoryNameResult
);
200 if ( categoryNameResult
== dyld3::MachOAnalyzer::PrintableStringResult::CanPrint
) {
201 ma
->forEachObjCMethod(objcCategory
.classMethodsVMAddr
, vmAddrConverter
, ^(uint64_t methodVMAddr
, const dyld3::MachOAnalyzer::ObjCMethod
& method
) {
202 dyld3::MachOAnalyzer::PrintableStringResult methodNameResult
;
203 const char* methodName
= ma
->getPrintableString(method
.nameVMAddr
, methodNameResult
);
204 if ( methodNameResult
== dyld3::MachOAnalyzer::PrintableStringResult::CanPrint
) {
205 if ( strcmp(methodName
, "load") == 0 ) {
206 // FIXME: if category is on class in another image, forEachObjCCategory returns null for objcCategory.clsVMAddr, need way to get name
207 __block
const char* catOnClassName
= "";
208 ma
->forEachObjCClass(diag
, vmAddrConverter
, ^(Diagnostics
& diag
, uint64_t classVMAddr
,
209 uint64_t classSuperclassVMAddr
, uint64_t classDataVMAddr
,
210 const dyld3::MachOAnalyzer::ObjCClassInfo
& objcClass
, bool isMetaClass
) {
211 if ( objcCategory
.clsVMAddr
== classVMAddr
) {
212 dyld3::MachOAnalyzer::PrintableStringResult classNameResult
;
213 const char* className
= ma
->getPrintableString(objcClass
.nameVMAddr(pointerSize
), classNameResult
);
214 if ( classNameResult
== dyld3::MachOAnalyzer::PrintableStringResult::CanPrint
) {
215 catOnClassName
= className
;
219 printf(" 0x%08llX +[%s(%s) %s]\n", methodVMAddr
-prefLoadAddress
, catOnClassName
, categoryName
, methodName
);
229 static const char* pointerFormat(uint16_t format
)
232 case DYLD_CHAINED_PTR_ARM64E
:
233 return "authenticated arm64e, 8-byte stride, target vmadddr";
234 case DYLD_CHAINED_PTR_ARM64E_USERLAND
:
235 return "authenticated arm64e, 8-byte stride, target vmoffset";
236 case DYLD_CHAINED_PTR_ARM64E_FIRMWARE
:
237 return "authenticated arm64e, 4-byte stride, target vmadddr";
238 case DYLD_CHAINED_PTR_ARM64E_KERNEL
:
239 return "authenticated arm64e, 4-byte stride, target vmoffset";
240 case DYLD_CHAINED_PTR_64
:
241 return "generic 64-bit, 4-byte stride, target vmadddr";
242 case DYLD_CHAINED_PTR_64_OFFSET
:
243 return "generic 64-bit, 4-byte stride, target vmoffset ";
244 case DYLD_CHAINED_PTR_32
:
245 return "generic 32-bit";
246 case DYLD_CHAINED_PTR_32_CACHE
:
247 return "32-bit for dyld cache";
248 case DYLD_CHAINED_PTR_64_KERNEL_CACHE
:
249 return "64-bit for kernel cache";
250 case DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE
:
251 return "64-bit for x86_64 kernel cache";
252 case DYLD_CHAINED_PTR_ARM64E_USERLAND24
:
253 return "authenticated arm64e, 8-byte stride, target vmoffset, 24-bit bind ordinals";
258 static void printChains(const dyld3::MachOAnalyzer
* ma
)
261 ma
->withChainStarts(diag
, 0, ^(const dyld_chained_starts_in_image
* starts
) {
262 for (int i
=0; i
< starts
->seg_count
; ++i
) {
263 if ( starts
->seg_info_offset
[i
] == 0 )
265 const dyld_chained_starts_in_segment
* seg
= (dyld_chained_starts_in_segment
*)((uint8_t*)starts
+ starts
->seg_info_offset
[i
]);
266 if ( seg
->page_count
== 0 )
268 printf("seg[%d]:\n", i
);
269 printf(" page_size: 0x%04X\n", seg
->page_size
);
270 printf(" pointer_format: %d (%s)\n", seg
->pointer_format
, pointerFormat(seg
->pointer_format
));
271 printf(" segment_offset: 0x%08llX\n", seg
->segment_offset
);
272 printf(" max_pointer: 0x%08X\n", seg
->max_valid_pointer
);
273 printf(" pages: %d\n", seg
->page_count
);
274 for (int pageIndex
=0; pageIndex
< seg
->page_count
; ++pageIndex
) {
275 uint16_t offsetInPage
= seg
->page_start
[pageIndex
];
276 if ( offsetInPage
== DYLD_CHAINED_PTR_START_NONE
)
278 if ( offsetInPage
& DYLD_CHAINED_PTR_START_MULTI
) {
279 // 32-bit chains which may need multiple starts per page
280 uint32_t overflowIndex
= offsetInPage
& ~DYLD_CHAINED_PTR_START_MULTI
;
281 bool chainEnd
= false;
283 chainEnd
= (seg
->page_start
[overflowIndex
] & DYLD_CHAINED_PTR_START_LAST
);
284 offsetInPage
= (seg
->page_start
[overflowIndex
] & ~DYLD_CHAINED_PTR_START_LAST
);
285 printf(" start[% 2d]: 0x%04X\n", pageIndex
, offsetInPage
);
290 // one chain per page
291 printf(" start[% 2d]: 0x%04X\n", pageIndex
, offsetInPage
);
299 static void printChainDetails(const dyld3::MachOAnalyzer
* ma
)
301 __block Diagnostics diag
;
302 ma
->withChainStarts(diag
, 0, ^(const dyld_chained_starts_in_image
* starts
) {
303 ma
->forEachFixupInAllChains(diag
, starts
, true, ^(ChainedFixupPointerOnDisk
* fixupLoc
, const dyld_chained_starts_in_segment
* segInfo
, bool& stop
) {
304 uint64_t vmOffset
= (uint8_t*)fixupLoc
- (uint8_t*)ma
;
305 switch (segInfo
->pointer_format
) {
306 case DYLD_CHAINED_PTR_ARM64E
:
307 case DYLD_CHAINED_PTR_ARM64E_KERNEL
:
308 case DYLD_CHAINED_PTR_ARM64E_USERLAND
:
309 case DYLD_CHAINED_PTR_ARM64E_FIRMWARE
:
310 case DYLD_CHAINED_PTR_ARM64E_USERLAND24
:
311 if ( fixupLoc
->arm64e
.authRebase
.auth
) {
312 uint32_t bindOrdinal
= (segInfo
->pointer_format
== DYLD_CHAINED_PTR_ARM64E_USERLAND24
) ? fixupLoc
->arm64e
.authBind24
.ordinal
: fixupLoc
->arm64e
.authBind
.ordinal
;
313 if ( fixupLoc
->arm64e
.authBind
.bind
) {
314 printf(" 0x%08llX: raw: 0x%016llX auth-bind: (next: %03d, key: %s, addrDiv: %d, diversity: 0x%04X, ordinal: %04X)\n", vmOffset
, fixupLoc
->raw64
,
315 fixupLoc
->arm64e
.authBind
.next
, fixupLoc
->arm64e
.keyName(),
316 fixupLoc
->arm64e
.authBind
.addrDiv
, fixupLoc
->arm64e
.authBind
.diversity
, bindOrdinal
);
319 printf(" 0x%08llX: raw: 0x%016llX auth-rebase: (next: %03d, key: %s, addrDiv: %d, diversity: 0x%04X, target: 0x%08X)\n", vmOffset
, fixupLoc
->raw64
,
320 fixupLoc
->arm64e
.authRebase
.next
, fixupLoc
->arm64e
.keyName(),
321 fixupLoc
->arm64e
.authBind
.addrDiv
, fixupLoc
->arm64e
.authBind
.diversity
, fixupLoc
->arm64e
.authRebase
.target
);
325 uint32_t bindOrdinal
= (segInfo
->pointer_format
== DYLD_CHAINED_PTR_ARM64E_USERLAND24
) ? fixupLoc
->arm64e
.bind24
.ordinal
: fixupLoc
->arm64e
.bind
.ordinal
;
326 if ( fixupLoc
->arm64e
.rebase
.bind
) {
327 printf(" 0x%08llX: raw: 0x%016llX bind: (next: %03d, ordinal: %04X, addend: %d)\n", vmOffset
, fixupLoc
->raw64
,
328 fixupLoc
->arm64e
.bind
.next
, bindOrdinal
, fixupLoc
->arm64e
.bind
.addend
);
331 printf(" 0x%08llX: raw: 0x%016llX rebase: (next: %03d, target: 0x%011llX, high8: 0x%02X)\n", vmOffset
, fixupLoc
->raw64
,
332 fixupLoc
->arm64e
.rebase
.next
, fixupLoc
->arm64e
.rebase
.target
, fixupLoc
->arm64e
.rebase
.high8
);
336 case DYLD_CHAINED_PTR_64
:
337 case DYLD_CHAINED_PTR_64_OFFSET
:
338 if ( fixupLoc
->generic64
.rebase
.bind
) {
339 printf(" 0x%08llX: raw: 0x%016llX bind: (next: %03d, ordinal: %06X, addend: %d)\n", vmOffset
, fixupLoc
->raw64
,
340 fixupLoc
->generic64
.bind
.next
, fixupLoc
->generic64
.bind
.ordinal
, fixupLoc
->generic64
.bind
.addend
);
343 printf(" 0x%08llX: raw: 0x%016llX rebase: (next: %03d, target: 0x%011llX, high8: 0x%02X)\n", vmOffset
, fixupLoc
->raw64
,
344 fixupLoc
->generic64
.rebase
.next
, fixupLoc
->generic64
.rebase
.target
, fixupLoc
->generic64
.rebase
.high8
);
347 case DYLD_CHAINED_PTR_32
:
348 if ( fixupLoc
->generic32
.bind
.bind
) {
349 printf(" 0x%08llX: raw: 0x%08X bind: (next:%02d ordinal:%05X addend:%d)\n", vmOffset
, fixupLoc
->raw32
,
350 fixupLoc
->generic32
.bind
.next
, fixupLoc
->generic32
.bind
.ordinal
, fixupLoc
->generic32
.bind
.addend
);
352 else if ( fixupLoc
->generic32
.rebase
.target
> segInfo
->max_valid_pointer
) {
353 uint32_t bias
= (0x04000000 + segInfo
->max_valid_pointer
)/2;
354 uint32_t value
= fixupLoc
->generic32
.rebase
.target
- bias
;
355 printf(" 0x%08llX: raw: 0x%08X nonptr: (next:%02d value: 0x%08X)\n", vmOffset
, fixupLoc
->raw32
,
356 fixupLoc
->generic32
.rebase
.next
, value
);
359 printf(" 0x%08llX: raw: 0x%08X rebase: (next:%02d target: 0x%07X)\n", vmOffset
, fixupLoc
->raw32
,
360 fixupLoc
->generic32
.rebase
.next
, fixupLoc
->generic32
.rebase
.target
);
364 fprintf(stderr
, "unknown pointer type %d\n", segInfo
->pointer_format
);
369 if ( diag
.hasError() )
370 fprintf(stderr
, "dyldinfo: %s\n", diag
.errorMessage());
377 std::string sectName
;
379 dyld3::MachOAnalyzerSet::PointerMetaData pmd
;
381 uint64_t targetValue
;
382 const char* targetDylib
;
383 const char* targetSymbolName
;
384 uint64_t targetAddend
;
385 bool targetWeakImport
;
389 struct SymbolicFixupInfo
398 static const char* ordinalName(const dyld3::MachOAnalyzer
* ma
, int libraryOrdinal
)
400 static int sLastOrdinal
= -100;
401 static const char* sLastString
= nullptr;
402 if ( libraryOrdinal
> 0 ) {
403 if ( libraryOrdinal
!= sLastOrdinal
) {
404 const char* path
= ma
->dependentDylibLoadPath(libraryOrdinal
-1);
405 if ( path
== nullptr )
406 return "ordinal-too-large";
407 const char* leafName
= path
;
408 if ( const char* lastSlash
= strrchr(path
, '/') )
409 leafName
= lastSlash
+1;
410 sLastOrdinal
= libraryOrdinal
;
411 sLastString
= leafName
;
416 switch ( libraryOrdinal
) {
417 case BIND_SPECIAL_DYLIB_SELF
:
419 case BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
:
420 return "main-executable";
421 case BIND_SPECIAL_DYLIB_FLAT_LOOKUP
:
422 return "flat-namespace";
423 case BIND_SPECIAL_DYLIB_WEAK_LOOKUP
:
424 return "weak-coalesce";
427 return "unknown-ordinal";
434 SectionFinder(const dyld3::MachOAnalyzer
* ma
);
435 const char* segmentName(uint64_t vmOffset
) const;
436 const char* sectionName(uint64_t vmOffset
) const;
437 uint64_t baseAddress() const { return _baseAddress
; }
438 uint64_t currentSectionAddress() const { return _lastSection
.sectAddr
; }
439 bool isNewSection(uint64_t vmOffset
) const;
442 void updateLastSection(uint64_t vmOffset
) const;
444 const dyld3::MachOAnalyzer
* _ma
;
445 uint64_t _baseAddress
;
446 mutable dyld3::MachOFile::SectionInfo _lastSection
;
447 mutable char _lastSegName
[20];
448 mutable char _lastSectName
[20];
451 SectionFinder::SectionFinder(const dyld3::MachOAnalyzer
* ma
)
454 _baseAddress
= ma
->preferredLoadAddress();
455 _lastSection
.sectAddr
= 0;
456 _lastSection
.sectSize
= 0;
459 bool SectionFinder::isNewSection(uint64_t vmOffset
) const
461 uint64_t vmAddr
= _baseAddress
+ vmOffset
;
462 return ( (vmAddr
< _lastSection
.sectAddr
) || (vmAddr
>= _lastSection
.sectAddr
+_lastSection
.sectSize
) );
465 void SectionFinder::updateLastSection(uint64_t vmOffset
) const
467 if ( isNewSection(vmOffset
) ) {
468 _lastSegName
[0] = '\0';
469 _lastSectName
[0] = '\0';
470 uint64_t vmAddr
= _baseAddress
+ vmOffset
;
471 _ma
->forEachSection(^(const dyld3::MachOFile::SectionInfo
& sectInfo
, bool malformedSectionRange
, bool& sectStop
) {
472 if ( (sectInfo
.sectAddr
<= vmAddr
) && (vmAddr
< sectInfo
.sectAddr
+sectInfo
.sectSize
) ) {
473 _lastSection
= sectInfo
;
474 strcpy(_lastSegName
, _lastSection
.segInfo
.segName
);
475 strcpy(_lastSectName
, _lastSection
.sectName
);
482 const char* SectionFinder::segmentName(uint64_t vmOffset
) const
484 updateLastSection(vmOffset
);
488 const char* SectionFinder::sectionName(uint64_t vmOffset
) const
490 updateLastSection(vmOffset
);
491 return _lastSectName
;
495 static inline std::string
decimal(int64_t value
) {
497 sprintf(buff
, "%lld", value
);
501 static inline std::string
hex(int64_t value
) {
503 sprintf(buff
, "0x%llX", value
);
507 static std::string
rebaseTargetString(const dyld3::MachOAnalyzer
* ma
, uint64_t vmAddr
)
509 uint64_t targetLoadAddr
= (uint64_t)ma
+vmAddr
;
510 const char* targetSymbolName
;
511 uint64_t targetSymbolLoadAddr
;
512 if ( ma
->findClosestSymbol(targetLoadAddr
, &targetSymbolName
, &targetSymbolLoadAddr
) ) {
513 uint64_t delta
= targetLoadAddr
- targetSymbolLoadAddr
;
515 return targetSymbolName
;
518 if ( (delta
== 1) && (ma
->cputype
== CPU_TYPE_ARM
) )
519 return std::string(targetSymbolName
) + std::string(" [thumb]");
521 return std::string(targetSymbolName
) + std::string("+") + decimal(delta
);
525 __block
std::string result
;
526 ma
->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo
& sectInfo
, bool malformedSectionRange
, bool& stop
) {
527 if ( (sectInfo
.sectAddr
<= vmAddr
) && (vmAddr
< sectInfo
.sectAddr
+sectInfo
.sectSize
) ) {
528 if ( (sectInfo
.sectFlags
& SECTION_TYPE
) == S_CSTRING_LITERALS
) {
529 const char* cstring
= (char*)ma
+ (vmAddr
-ma
->preferredLoadAddress());
530 result
= std::string("\"") + cstring
+ std::string("\"");
533 result
= std::string(sectInfo
.segInfo
.segName
) + "/" + sectInfo
.sectName
+ "+" + decimal(vmAddr
- sectInfo
.sectAddr
);
543 typedef dyld3::MachOAnalyzerSet MachOAnalyzerSet
;
544 typedef dyld3::MachOAnalyzerSet::WrappedMachO WrappedMachO
;
546 struct InfoAnalyzerSet
: public MachOAnalyzerSet
548 void mas_forEachImage(void (^handler
)(const WrappedMachO
& anImage
, bool hidden
, bool& stop
)) const override
;
549 void mas_mainExecutable(WrappedMachO
& anImage
) const override
;
550 void* mas_dyldCache() const override
;
551 bool wmo_dependent(const WrappedMachO
* image
, uint32_t depIndex
, WrappedMachO
& childObj
, bool& missingWeakDylib
) const override
;
552 const char* wmo_path(const WrappedMachO
* image
) const override
;
553 ExportsTrie
wmo_getExportsTrie(const WrappedMachO
* image
) const override
;
554 bool wmo_findSymbolFrom(const WrappedMachO
* fromWmo
, Diagnostics
& diag
, int libOrdinal
, const char* symbolName
, bool weakImport
,
555 bool lazyBind
, uint64_t addend
, CachePatchHandler ph
, FixupTarget
& target
) const override
;
556 bool wmo_missingSymbolResolver(const WrappedMachO
* fromWmo
, bool weakImport
, bool lazyBind
, const char* symbolName
, const char* expectedInDylibPath
, const char* clientPath
, FixupTarget
& target
) const override
;
559 bool InfoAnalyzerSet::wmo_dependent(const WrappedMachO
* image
, uint32_t depIndex
, WrappedMachO
& childObj
, bool& missingWeakDylib
) const
561 const char* depPath
= image
->_mh
->dependentDylibLoadPath(depIndex
);
562 childObj
= WrappedMachO(nullptr, image
->_set
, (void*)depPath
);
566 const char* InfoAnalyzerSet::wmo_path(const WrappedMachO
* image
) const
568 return (const char*)image
->_other
;
571 MachOAnalyzerSet::ExportsTrie
InfoAnalyzerSet::wmo_getExportsTrie(const WrappedMachO
* obj
) const
573 return { nullptr, nullptr };
576 bool InfoAnalyzerSet::wmo_findSymbolFrom(const WrappedMachO
* obj
, Diagnostics
& diag
, int libOrdinal
, const char* symbolName
, bool weakImport
,
577 bool lazyBind
, uint64_t addend
, CachePatchHandler ph
, MachOAnalyzerSet::FixupTarget
& target
) const
579 target
.requestedSymbolName
= symbolName
;
580 target
.foundSymbolName
= symbolName
;
581 target
.addend
= addend
;
582 target
.kind
= weakImport
? MachOAnalyzerSet::FixupTarget::Kind::bindMissingSymbol
: MachOAnalyzerSet::FixupTarget::Kind::bindToImage
;
583 if ( libOrdinal
== BIND_SPECIAL_DYLIB_SELF
) {
584 target
.foundInImage
= WrappedMachO(nullptr, obj
->_set
, (void*)"self");
586 else if ( libOrdinal
== BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
) {
587 target
.foundInImage
= WrappedMachO(nullptr, obj
->_set
, (void*)"main-executable");
589 else if ( libOrdinal
== BIND_SPECIAL_DYLIB_FLAT_LOOKUP
) {
590 target
.foundInImage
= WrappedMachO(nullptr, obj
->_set
, (void*)"flat-namespace");
592 else if ( libOrdinal
== BIND_SPECIAL_DYLIB_WEAK_LOOKUP
) {
593 target
.foundInImage
= WrappedMachO(nullptr, obj
->_set
, (void*)"weak-coalesce");
596 int depIndex
= libOrdinal
- 1;
597 const char* depPath
= obj
->_mh
->dependentDylibLoadPath(depIndex
);
598 const char* lastSlash
= strrchr(depPath
, '/');
603 target
.foundInImage
= WrappedMachO(nullptr, obj
->_set
, (void*)lastSlash
);
608 void InfoAnalyzerSet::mas_forEachImage(void (^handler
)(const WrappedMachO
& anImage
, bool hidden
, bool& stop
)) const
610 WrappedMachO
anImage(nullptr, this, (void*)"flat-namespace");
612 handler(anImage
, false, stop
);
616 bool InfoAnalyzerSet::wmo_missingSymbolResolver(const WrappedMachO
* fromWmo
, bool weakImport
, bool lazyBind
, const char* symbolName
, const char* expectedInDylibPath
, const char* clientPath
, FixupTarget
& target
) const
621 void InfoAnalyzerSet::mas_mainExecutable(WrappedMachO
& anImage
) const
623 anImage
= WrappedMachO(nullptr, this, (void*)"main-executable");
626 void* InfoAnalyzerSet::mas_dyldCache() const
631 static void printFixups(const dyld3::MachOAnalyzer
* ma
, const char* path
)
633 printf(" -fixups:\n");
635 __block
std::vector
<FixupInfo
> fixups
;
636 uint64_t prefLoadAddr
= ma
->preferredLoadAddress();
637 SectionFinder
namer(ma
);
639 WrappedMachO
wm(ma
, &ias
, (void*)path
);
640 wm
.forEachFixup(diag
, ^(uint64_t fixupLocRuntimeOffset
, MachOAnalyzerSet::PointerMetaData pmd
, const MachOAnalyzerSet::FixupTarget
& target
, bool& stop
) {
642 fixup
.segName
= namer
.segmentName(fixupLocRuntimeOffset
);
643 fixup
.sectName
= namer
.sectionName(fixupLocRuntimeOffset
);
644 fixup
.address
= prefLoadAddr
+ fixupLocRuntimeOffset
;
646 fixup
.targetWeakImport
= false;
647 switch ( target
.kind
) {
648 case MachOAnalyzerSet::FixupTarget::Kind::bindAbsolute
:
649 fixup
.type
= "absolute";
651 case MachOAnalyzerSet::FixupTarget::Kind::rebase
:
652 fixup
.type
= "rebase";
653 fixup
.targetSymbolName
= nullptr;
654 fixup
.targetDylib
= nullptr;
656 case MachOAnalyzerSet::FixupTarget::Kind::bindToImage
:
658 fixup
.targetSymbolName
= target
.requestedSymbolName
;
659 fixup
.targetDylib
= target
.foundInImage
.path();
661 case MachOAnalyzerSet::FixupTarget::Kind::bindMissingSymbol
:
663 fixup
.targetSymbolName
= target
.requestedSymbolName
;
664 fixup
.targetDylib
= target
.foundInImage
.path();
665 fixup
.targetWeakImport
= true;
668 fixup
.targetValue
= target
.offsetInImage
;
669 fixup
.targetAddend
= target
.addend
;
671 fixup
.targetAddend
+= ((uint64_t)pmd
.high8
<< 56);
672 fixups
.push_back(fixup
);
674 ^(uint32_t, uint32_t, const MachOAnalyzerSet::FixupTarget
&) {
677 std::sort(fixups
.begin(), fixups
.end(), [](const FixupInfo
& l
, const FixupInfo
& r
) {
680 if ( l
.address
== r
.address
)
681 return (l
.targetSymbolName
== nullptr);
682 return ( l
.address
< r
.address
);
685 printf(" segment section address type target\n");
686 for (const FixupInfo
& fixup
: fixups
) {
689 if ( fixup
.pmd
.authenticated
) {
690 sprintf(authInfo
, " (div=0x%04X ad=%d key=%s)", fixup
.pmd
.diversity
, fixup
.pmd
.usesAddrDiversity
, ChainedFixupPointerOnDisk::Arm64e::keyName(fixup
.pmd
.key
));
692 if ( fixup
.targetSymbolName
== nullptr )
693 printf(" %-12s %-16s 0x%08llX %16s 0x%08llX%s\n", fixup
.segName
.c_str(), fixup
.sectName
.c_str(), fixup
.address
, fixup
.type
, fixup
.targetValue
, authInfo
);
694 else if ( fixup
.targetAddend
!= 0 )
695 printf(" %-12s %-16s 0x%08llX %16s %s/%s + 0x%llX%s\n", fixup
.segName
.c_str(), fixup
.sectName
.c_str(), fixup
.address
, fixup
.type
, fixup
.targetDylib
, fixup
.targetSymbolName
, fixup
.targetAddend
, authInfo
);
696 else if ( fixup
.targetWeakImport
)
697 printf(" %-12s %-16s 0x%08llX %16s %s/%s [weak-import]%s\n", fixup
.segName
.c_str(), fixup
.sectName
.c_str(), fixup
.address
, fixup
.type
, fixup
.targetDylib
, fixup
.targetSymbolName
, authInfo
);
699 printf(" %-12s %-16s 0x%08llX %16s %s/%s%s\n", fixup
.segName
.c_str(), fixup
.sectName
.c_str(), fixup
.address
, fixup
.type
, fixup
.targetDylib
, fixup
.targetSymbolName
, authInfo
);
703 static void printSymbolicFixups(const dyld3::MachOAnalyzer
* ma
, const char* path
)
705 printf(" -symbolic_fixups:\n");
707 __block
std::vector
<SymbolicFixupInfo
> fixups
;
708 uint64_t prefLoadAddr
= ma
->preferredLoadAddress();
710 WrappedMachO
wm(ma
, &ias
, (void*)path
);
711 wm
.forEachFixup(diag
, ^(uint64_t fixupLocRuntimeOffset
, MachOAnalyzerSet::PointerMetaData pmd
, const MachOAnalyzerSet::FixupTarget
& target
, bool& stop
) {
712 SymbolicFixupInfo fixup
;
713 fixup
.address
= prefLoadAddr
+ fixupLocRuntimeOffset
;
714 switch ( target
.kind
) {
715 case MachOAnalyzerSet::FixupTarget::Kind::bindAbsolute
:
716 fixup
.kind
= "absolute";
719 case MachOAnalyzerSet::FixupTarget::Kind::rebase
:
720 fixup
.kind
= "rebase pointer";
721 fixup
.target
= rebaseTargetString(ma
, target
.offsetInImage
);
723 case MachOAnalyzerSet::FixupTarget::Kind::bindToImage
:
724 case MachOAnalyzerSet::FixupTarget::Kind::bindMissingSymbol
:
725 fixup
.kind
= "bind pointer";
726 fixup
.target
= std::string(target
.foundInImage
.path()) + "/" + target
.requestedSymbolName
;
727 if ( target
.addend
!= 0 )
728 fixup
.target
+= std::string("+") + decimal(target
.addend
);
730 fixup
.target
+= std::string("+") + hex(((uint64_t)pmd
.high8
<< 56));
731 //if ( target.weakImport )
732 // fixup.target += " [weak-import]";
735 if ( pmd
.authenticated
) {
737 sprintf(authInfo
, " (div=0x%04X ad=%d key=%s)", pmd
.diversity
, pmd
.usesAddrDiversity
, ChainedFixupPointerOnDisk::Arm64e::keyName(pmd
.key
));
738 fixup
.target
+= authInfo
;
740 fixups
.push_back(fixup
);
742 ^(uint32_t, uint32_t, const MachOAnalyzerSet::FixupTarget
&) {
746 std::sort(fixups
.begin(), fixups
.end(), [](const SymbolicFixupInfo
& l
, const SymbolicFixupInfo
& r
) {
749 return ( l
.address
< r
.address
);
752 SectionFinder
sectionTracker(ma
);
753 uint64_t lastSymbolVmOffset
= 0;
754 for (const SymbolicFixupInfo
& fixup
: fixups
) {
755 uint64_t vmAddr
= fixup
.address
;
756 uint64_t vmOffset
= vmAddr
- prefLoadAddr
;
757 if ( sectionTracker
.isNewSection(vmOffset
) ) {
758 printf(" 0x%08llX %-12s %-16s \n", vmAddr
, sectionTracker
.segmentName(vmOffset
), sectionTracker
.sectionName(vmOffset
));
760 const char* symbolName
;
761 uint64_t symbolLoadAddr
= 0;
762 if ( ma
->findClosestSymbol((uint64_t)ma
+vmOffset
, &symbolName
, &symbolLoadAddr
) ) {
763 uint64_t symbolVmOffset
= symbolLoadAddr
- (uint64_t)ma
;
764 if ( symbolVmOffset
!= lastSymbolVmOffset
) {
765 printf(" %s:\n", symbolName
);
766 lastSymbolVmOffset
= symbolVmOffset
;
769 printf(" +0x%04llX %16s %s\n", vmOffset
- lastSymbolVmOffset
, fixup
.kind
, fixup
.target
.c_str());
774 static void printExports(const dyld3::MachOAnalyzer
* ma
)
776 printf(" -exports:\n");
777 printf(" offset symbol\n");
779 ma
->forEachExportedSymbol(diag
, ^(const char* symbolName
, uint64_t imageOffset
, uint64_t flags
, uint64_t other
, const char* importName
, bool& stop
) {
780 //printf("0x%08llX %s\n", imageOffset, symbolName);
781 const bool reExport
= (flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
);
782 const bool weakDef
= (flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
);
783 const bool resolver
= (flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
);
784 const bool threadLocal
= ((flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
);
785 const bool abs
= ((flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
);
787 printf(" [re-export] ");
789 printf(" 0x%08llX ", imageOffset
);
790 printf("%s", symbolName
);
791 if ( weakDef
|| threadLocal
|| resolver
|| abs
) {
792 bool needComma
= false;
801 printf("per-thread");
813 printf("resolver=0x%08llX", other
);
819 if ( importName
[0] == '\0' )
820 printf(" (from %s)", ordinalName(ma
, (int)other
));
822 printf(" (%s from %s)", importName
, ordinalName(ma
, (int)other
));
829 static void printObjC(const dyld3::MachOAnalyzer
* ma
, const DyldSharedCache
* dyldCache
, size_t cacheLen
)
832 const uint32_t pointerSize
= ma
->pointerSize();
833 const dyld3::MachOAnalyzer::VMAddrConverter vmAddrConverter
= (ma
->inDyldCache() ? dyldCache
->makeVMAddrConverter(true) : ma
->makeVMAddrConverter(false));
835 auto printMethod
= ^(uint64_t methodVMAddr
, const dyld3::MachOAnalyzer::ObjCMethod
& method
) {
836 const char* type
= "method";
837 dyld3::MachOAnalyzer::PrintableStringResult methodNameResult
;
838 const char* methodName
= ma
->getPrintableString(method
.nameVMAddr
, methodNameResult
);
839 switch (methodNameResult
) {
840 case dyld3::MachOAnalyzer::PrintableStringResult::CanPrint
:
841 // The string is already valid
843 case dyld3::MachOAnalyzer::PrintableStringResult::FairPlayEncrypted
:
844 methodName
= "### fairplay encrypted";
846 case dyld3::MachOAnalyzer::PrintableStringResult::ProtectedSection
:
847 methodName
= "### protected section";
849 case dyld3::MachOAnalyzer::PrintableStringResult::UnknownSection
:
850 methodName
= "### unknown section";
853 printf(" %10s 0x%08llX %s\n",
854 type
, methodVMAddr
, methodName
);
858 // can't inspect ObjC of a live dylib
859 if ( liveMachO(ma
, dyldCache
, cacheLen
) ) {
860 printf(" <<<cannot print objc data on live dylib>>>\n");
863 printf(" type vmaddr data-vmaddr name\n");
864 auto printClass
= ^(Diagnostics
& diag
, uint64_t classVMAddr
,
865 uint64_t classSuperclassVMAddr
, uint64_t classDataVMAddr
,
866 const dyld3::MachOAnalyzer::ObjCClassInfo
& objcClass
, bool isMetaClass
) {
867 const char* type
= "class";
870 dyld3::MachOAnalyzer::PrintableStringResult classNameResult
;
871 const char* className
= ma
->getPrintableString(objcClass
.nameVMAddr(pointerSize
), classNameResult
);
872 switch (classNameResult
) {
873 case dyld3::MachOAnalyzer::PrintableStringResult::CanPrint
:
874 // The string is already valid
876 case dyld3::MachOAnalyzer::PrintableStringResult::FairPlayEncrypted
:
877 className
= "### fairplay encrypted";
879 case dyld3::MachOAnalyzer::PrintableStringResult::ProtectedSection
:
880 className
= "### protected section";
882 case dyld3::MachOAnalyzer::PrintableStringResult::UnknownSection
:
883 className
= "### unknown section";
886 printf(" %10s 0x%08llX 0x%08llX %s\n",
887 type
, classVMAddr
, objcClass
.dataVMAddr
, className
);
889 // Now print the methods on this class
890 ma
->forEachObjCMethod(objcClass
.baseMethodsVMAddr(pointerSize
), vmAddrConverter
, printMethod
);
892 auto printCategory
= ^(Diagnostics
& diag
, uint64_t categoryVMAddr
,
893 const dyld3::MachOAnalyzer::ObjCCategory
& objcCategory
) {
894 const char* type
= "category";
895 dyld3::MachOAnalyzer::PrintableStringResult categoryNameResult
;
896 const char* categoryName
= ma
->getPrintableString(objcCategory
.nameVMAddr
, categoryNameResult
);
897 switch (categoryNameResult
) {
898 case dyld3::MachOAnalyzer::PrintableStringResult::CanPrint
:
899 // The string is already valid
901 case dyld3::MachOAnalyzer::PrintableStringResult::FairPlayEncrypted
:
902 categoryName
= "### fairplay encrypted";
904 case dyld3::MachOAnalyzer::PrintableStringResult::ProtectedSection
:
905 categoryName
= "### protected section";
907 case dyld3::MachOAnalyzer::PrintableStringResult::UnknownSection
:
908 categoryName
= "### unknown section";
911 printf(" %10s 0x%08llX %s\n",
912 type
, categoryVMAddr
, categoryName
);
914 // Now print the methods on this category
915 ma
->forEachObjCMethod(objcCategory
.instanceMethodsVMAddr
, vmAddrConverter
,
917 ma
->forEachObjCMethod(objcCategory
.classMethodsVMAddr
, vmAddrConverter
,
920 auto printProtocol
= ^(Diagnostics
& diag
, uint64_t protocolVMAddr
,
921 const dyld3::MachOAnalyzer::ObjCProtocol
& objCProtocol
) {
922 const char* type
= "protocol";
923 dyld3::MachOAnalyzer::PrintableStringResult protocolNameResult
;
924 const char* protocolName
= ma
->getPrintableString(objCProtocol
.nameVMAddr
, protocolNameResult
);
925 switch (protocolNameResult
) {
926 case dyld3::MachOAnalyzer::PrintableStringResult::CanPrint
:
927 // The string is already valid
929 case dyld3::MachOAnalyzer::PrintableStringResult::FairPlayEncrypted
:
930 protocolName
= "### fairplay encrypted";
932 case dyld3::MachOAnalyzer::PrintableStringResult::ProtectedSection
:
933 protocolName
= "### protected section";
935 case dyld3::MachOAnalyzer::PrintableStringResult::UnknownSection
:
936 protocolName
= "### unknown section";
939 printf(" %10s 0x%08llX %s\n",
940 type
, protocolVMAddr
, protocolName
);
942 // Now print the methods on this protocol
943 ma
->forEachObjCMethod(objCProtocol
.instanceMethodsVMAddr
, vmAddrConverter
,
945 ma
->forEachObjCMethod(objCProtocol
.classMethodsVMAddr
, vmAddrConverter
,
947 ma
->forEachObjCMethod(objCProtocol
.optionalInstanceMethodsVMAddr
, vmAddrConverter
,
949 ma
->forEachObjCMethod(objCProtocol
.optionalClassMethodsVMAddr
, vmAddrConverter
,
952 ma
->forEachObjCClass(diag
, vmAddrConverter
, printClass
);
953 ma
->forEachObjCCategory(diag
, vmAddrConverter
, printCategory
);
954 ma
->forEachObjCProtocol(diag
, vmAddrConverter
, printProtocol
);
959 fprintf(stderr
, "Usage: dyldinfo [-arch <arch>]* <options>* <mach-o file>+\n"
960 "\t-segments print segments\n"
961 "\t-dependents print dependent dylibs\n"
962 "\t-fixups print locations dyld will rebase/bind\n"
963 "\t-exports print addresses of all symbols this file exports\n"
964 "\t-objc print objc classes, categories, etc\n"
968 static bool inStringVector(const std::vector
<const char*>& vect
, const char* target
)
970 for (const char* str
: vect
) {
971 if ( strcmp(str
, target
) == 0 )
978 int main(int argc
, const char* argv
[])
985 std::vector
<const char*> files
;
986 std::vector
<const char*> cmdLineArchs
;
987 for (int i
=1; i
< argc
; ++i
) {
988 const char* arg
= argv
[i
];
989 if ( arg
[0] == '-' ) {
990 if ( strcmp(arg
, "-arch") == 0 ) {
992 cmdLineArchs
.push_back(argv
[i
]);
995 fprintf(stderr
, "-arch missing architecture name");
1001 files
.push_back(arg
);
1004 if ( files
.size() == 0 ) {
1010 const DyldSharedCache
* cache
= (DyldSharedCache
*)_dyld_get_shared_cache_range(&cacheLen
);
1011 for (const char* path
: files
) {
1013 bool fromSharedCache
= false;
1014 dyld3::closure::FileSystemPhysical fileSystem
;
1015 dyld3::closure::LoadedFileInfo info
;
1016 __block
std::vector
<const char*> archesForFile
;
1017 char realerPath
[MAXPATHLEN
];
1018 __block
bool printedError
= false;
1019 if (!fileSystem
.loadFile(path
, info
, realerPath
, ^(const char* format
, ...) {
1020 fprintf(stderr
, "dyldinfo: ");
1022 va_start(list
, format
);
1023 vfprintf(stderr
, format
, list
);
1025 printedError
= true;
1029 // see if path is in current dyld shared cache
1030 info
.fileContent
= nullptr;
1031 if ( cache
!= nullptr ) {
1032 uint32_t imageIndex
;
1033 if ( cache
->hasImagePath(path
, imageIndex
) ) {
1036 const mach_header
* mh
= cache
->getIndexedImageEntry(imageIndex
, mTime
, inode
);
1037 info
.fileContent
= mh
;
1039 fromSharedCache
= true;
1040 archesForFile
.push_back(cache
->archName());
1043 if ( !fromSharedCache
) {
1044 fprintf(stderr
, "dyldinfo: %s: file not found\n", path
);
1048 __block
dyld3::Platform platform
= dyld3::Platform::unknown
;
1049 if ( dyld3::FatFile::isFatFile(info
.fileContent
) ) {
1050 const dyld3::FatFile
* ff
= (dyld3::FatFile
*)info
.fileContent
;
1051 ff
->forEachSlice(diag
, info
.fileContentLen
, ^(uint32_t sliceCpuType
, uint32_t sliceCpuSubType
, const void* sliceStart
, uint64_t sliceSize
, bool& stop
) {
1052 const char* sliceArchName
= dyld3::MachOFile::archName(sliceCpuType
, sliceCpuSubType
);
1053 if ( cmdLineArchs
.empty() || inStringVector(cmdLineArchs
, sliceArchName
) ) {
1054 archesForFile
.push_back(sliceArchName
);
1055 const dyld3::MachOFile
* mf
= (dyld3::MachOFile
*)sliceStart
;
1056 mf
->forEachSupportedPlatform(^(dyld3::Platform plat
, uint32_t minOS
, uint32_t sdk
) {
1057 if ( platform
== dyld3::Platform::unknown
)
1063 else if ( !fromSharedCache
) {
1064 const dyld3::MachOFile
* mo
= (dyld3::MachOFile
*)info
.fileContent
;
1065 if ( mo
->isMachO(diag
, info
.sliceLen
) ) {
1066 archesForFile
.push_back(mo
->archName());
1067 mo
->forEachSupportedPlatform(^(dyld3::Platform plat
, uint32_t minOS
, uint32_t sdk
) {
1068 if ( platform
== dyld3::Platform::unknown
)
1073 fprintf(stderr
, "dyldinfo: %s: %s\n", path
, diag
.errorMessage());
1077 if ( archesForFile
.empty() ) {
1078 fprintf(stderr
, "dyldinfo: %s: does not contain specified arch(s)\n", path
);
1081 char loadedPath
[MAXPATHLEN
];
1082 for (const char* sliceArch
: archesForFile
) {
1083 if ( !fromSharedCache
)
1084 info
= dyld3::MachOAnalyzer::load(diag
, fileSystem
, path
, dyld3::GradedArchs::forName(sliceArch
), platform
, loadedPath
);
1085 if ( diag
.hasError() ) {
1086 fprintf(stderr
, "dyldinfo: %s\n", diag
.errorMessage());
1089 const dyld3::MachOAnalyzer
* ma
= (dyld3::MachOAnalyzer
*)info
.fileContent
;
1090 printf("%s [%s]:\n", path
, sliceArch
);
1092 bool somethingPrinted
= false;
1093 for (int i
=1; i
< argc
; ++i
) {
1094 const char* arg
= argv
[i
];
1095 if ( arg
[0] != '-' )
1097 if ( strcmp(arg
, "-arch") == 0 ) {
1098 // handled previously
1101 else if ( strcmp(arg
, "-platform") == 0 ) {
1103 somethingPrinted
= true;
1105 else if ( strcmp(arg
, "-segments") == 0 ) {
1107 somethingPrinted
= true;
1109 else if ( strcmp(arg
, "-dependents") == 0 ) {
1110 printDependents(ma
);
1111 somethingPrinted
= true;
1113 else if ( strcmp(arg
, "-inits") == 0 ) {
1114 printInitializers(ma
, cache
, cacheLen
);
1115 somethingPrinted
= true;
1117 else if ( strcmp(arg
, "-fixups") == 0 ) {
1118 printFixups(ma
, path
);
1119 somethingPrinted
= true;
1121 else if ( strcmp(arg
, "-exports") == 0 ) {
1123 somethingPrinted
= true;
1125 else if ( strcmp(arg
, "-fixup_chains") == 0 ) {
1127 somethingPrinted
= true;
1129 else if ( strcmp(arg
, "-fixup_chain_details") == 0 ) {
1130 printChainDetails(ma
);
1131 somethingPrinted
= true;
1133 else if ( strcmp(arg
, "-symbolic_fixups") == 0 ) {
1134 printSymbolicFixups(ma
, path
);
1135 somethingPrinted
= true;
1137 else if ( strcmp(arg
, "-opcodes") == 0 ) {
1139 else if ( strcmp(arg
, "-shared_region") == 0 ) {
1141 else if ( strcmp(arg
, "-function_starts") == 0 ) {
1143 else if ( strcmp(arg
, "-data_in_code") == 0 ) {
1145 else if ( strcmp(arg
, "-objc") == 0 ) {
1146 printObjC(ma
, cache
, cacheLen
);
1147 somethingPrinted
= true;
1150 fprintf(stderr
, "unknown option: %s\n", arg
);
1154 if ( !somethingPrinted
) {
1157 printDependents(ma
);
1158 printInitializers(ma
, cache
, cacheLen
);
1159 printFixups(ma
, path
);
1161 printObjC(ma
, cache
, cacheLen
);