1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2009-2012 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@
34 #include <sys/syslimits.h>
35 #include <mach-o/arch.h>
36 #include <mach-o/loader.h>
37 #include <mach-o/dyld_priv.h>
38 #include <bootstrap.h>
39 #include <mach/mach.h>
40 #include <dispatch/dispatch.h>
42 #include <TargetConditionals.h>
48 #include "DyldSharedCache.h"
51 #include "objc-shared-cache.h"
54 #define DSC_BUNDLE_REL_PATH "../../lib/dsc_extractor.bundle"
56 #define DSC_BUNDLE_REL_PATH "../lib/dsc_extractor.bundle"
59 // mmap() an shared cache file read/only but laid out like it would be at runtime
60 static const DyldSharedCache
* mapCacheFile(const char* path
)
63 if ( ::stat(path
, &statbuf
) ) {
64 fprintf(stderr
, "Error: stat failed for dyld shared cache at %s\n", path
);
68 int cache_fd
= ::open(path
, O_RDONLY
);
70 fprintf(stderr
, "Error: failed to open shared cache file at %s\n", path
);
74 uint8_t firstPage
[4096];
75 if ( ::pread(cache_fd
, firstPage
, 4096, 0) != 4096 ) {
76 fprintf(stderr
, "Error: failed to read shared cache file at %s\n", path
);
79 const dyld_cache_header
* header
= (dyld_cache_header
*)firstPage
;
80 const dyld_cache_mapping_info
* mappings
= (dyld_cache_mapping_info
*)(firstPage
+ header
->mappingOffset
);
82 size_t vmSize
= (size_t)(mappings
[2].address
+ mappings
[2].size
- mappings
[0].address
);
84 kern_return_t r
= ::vm_allocate(mach_task_self(), &result
, vmSize
, VM_FLAGS_ANYWHERE
);
85 if ( r
!= KERN_SUCCESS
) {
86 fprintf(stderr
, "Error: failed to allocate space to load shared cache file at %s\n", path
);
89 for (int i
=0; i
< 3; ++i
) {
90 void* mapped_cache
= ::mmap((void*)(result
+ mappings
[i
].address
- mappings
[0].address
), (size_t)mappings
[i
].size
,
91 PROT_READ
, MAP_FIXED
| MAP_PRIVATE
, cache_fd
, mappings
[i
].fileOffset
);
92 if (mapped_cache
== MAP_FAILED
) {
93 fprintf(stderr
, "Error: mmap() for shared cache at %s failed, errno=%d\n", path
, errno
);
99 return (DyldSharedCache
*)result
;
108 modeVerboseSlideInfo
,
125 const char* dependentsOfPath
;
126 const char* extractionDir
;
129 bool printDylibVersions
;
135 fprintf(stderr
, "Usage: dyld_shared_cache_util -list [ -uuid ] [-vmaddr] | -dependents <dylib-path> [ -versions ] | -linkedit | -map | -slide_info | -verbose_slide_info | -info | -extract <dylib-dir> [ shared-cache-file ] \n");
138 static void checkMode(Mode mode
) {
139 if ( mode
!= modeNone
) {
140 fprintf(stderr
, "Error: select one of: -list, -dependents, -info, -slide_info, -verbose_slide_info, -linkedit, -map, -extract, or -size\n");
146 static bool isAlias(const char* path
, const DyldSharedCache
* dyldCache
) {
147 const dyld_cache_header
* header
= &dyldCache
->header
;
148 const dyld_cache_mapping_info
* mappings
= (const dyld_cache_mapping_info
*)((char*)dyldCache
+ header
->mappingOffset
);
149 const dyld_cache_mapping_info
* textMapping
= &mappings
[0];
150 // paths for aliases are store between cache header and first segment
151 return path
< (char*)textMapping
;
154 int main (int argc
, const char* argv
[]) {
156 const char* sharedCachePath
= nullptr;
159 options
.mode
= modeNone
;
160 options
.printUUIDs
= false;
161 options
.printVMAddrs
= false;
162 options
.printDylibVersions
= false;
163 options
.printInodes
= false;
164 options
.dependentsOfPath
= NULL
;
165 options
.extractionDir
= NULL
;
167 bool printStrings
= false;
168 bool printExports
= false;
170 for (uint32_t i
= 1; i
< argc
; i
++) {
171 const char* opt
= argv
[i
];
173 if (strcmp(opt
, "-list") == 0) {
174 checkMode(options
.mode
);
175 options
.mode
= modeList
;
177 else if (strcmp(opt
, "-dependents") == 0) {
178 checkMode(options
.mode
);
179 options
.mode
= modeDependencies
;
180 options
.dependentsOfPath
= argv
[++i
];
182 fprintf(stderr
, "Error: option -depdendents requires an argument\n");
187 else if (strcmp(opt
, "-linkedit") == 0) {
188 checkMode(options
.mode
);
189 options
.mode
= modeLinkEdit
;
191 else if (strcmp(opt
, "-info") == 0) {
192 checkMode(options
.mode
);
193 options
.mode
= modeInfo
;
195 else if (strcmp(opt
, "-slide_info") == 0) {
196 checkMode(options
.mode
);
197 options
.mode
= modeSlideInfo
;
199 else if (strcmp(opt
, "-verbose_slide_info") == 0) {
200 checkMode(options
.mode
);
201 options
.mode
= modeVerboseSlideInfo
;
203 else if (strcmp(opt
, "-accelerator_info") == 0) {
204 checkMode(options
.mode
);
205 options
.mode
= modeAcceleratorInfo
;
207 else if (strcmp(opt
, "-text_info") == 0) {
208 checkMode(options
.mode
);
209 options
.mode
= modeTextInfo
;
211 else if (strcmp(opt
, "-local_symbols") == 0) {
212 checkMode(options
.mode
);
213 options
.mode
= modeLocalSymbols
;
215 else if (strcmp(opt
, "-strings") == 0) {
216 if (options
.mode
!= modeStrings
)
217 checkMode(options
.mode
);
218 options
.mode
= modeStrings
;
221 else if (strcmp(opt
, "-sections") == 0) {
222 checkMode(options
.mode
);
223 options
.mode
= modeSectionSizes
;
225 else if (strcmp(opt
, "-exports") == 0) {
226 if (options
.mode
!= modeStrings
)
227 checkMode(options
.mode
);
228 options
.mode
= modeStrings
;
231 else if (strcmp(opt
, "-map") == 0) {
232 checkMode(options
.mode
);
233 options
.mode
= modeMap
;
235 else if (strcmp(opt
, "-json-map") == 0) {
236 checkMode(options
.mode
);
237 options
.mode
= modeJSONMap
;
239 else if (strcmp(opt
, "-json-dependents") == 0) {
240 checkMode(options
.mode
);
241 options
.mode
= modeJSONDependents
;
243 else if (strcmp(opt
, "-size") == 0) {
244 checkMode(options
.mode
);
245 options
.mode
= modeSize
;
247 else if (strcmp(opt
, "-objc-protocols") == 0) {
248 checkMode(options
.mode
);
249 options
.mode
= modeObjCProtocols
;
251 else if (strcmp(opt
, "-extract") == 0) {
252 checkMode(options
.mode
);
253 options
.mode
= modeExtract
;
254 options
.extractionDir
= argv
[++i
];
256 fprintf(stderr
, "Error: option -extract requires a directory argument\n");
261 else if (strcmp(opt
, "-uuid") == 0) {
262 options
.printUUIDs
= true;
264 else if (strcmp(opt
, "-inode") == 0) {
265 options
.printInodes
= true;
267 else if (strcmp(opt
, "-versions") == 0) {
268 options
.printDylibVersions
= true;
270 else if (strcmp(opt
, "-vmaddr") == 0) {
271 options
.printVMAddrs
= true;
274 fprintf(stderr
, "Error: unrecognized option %s\n", opt
);
280 sharedCachePath
= opt
;
284 if ( options
.mode
== modeNone
) {
285 fprintf(stderr
, "Error: select one of -list, -dependents, -info, -linkedit, or -map\n");
290 if ( options
.mode
!= modeSlideInfo
&& options
.mode
!= modeVerboseSlideInfo
) {
291 if ( options
.printUUIDs
&& (options
.mode
!= modeList
) )
292 fprintf(stderr
, "Warning: -uuid option ignored outside of -list mode\n");
294 if ( options
.printVMAddrs
&& (options
.mode
!= modeList
) )
295 fprintf(stderr
, "Warning: -vmaddr option ignored outside of -list mode\n");
297 if ( options
.printDylibVersions
&& (options
.mode
!= modeDependencies
) )
298 fprintf(stderr
, "Warning: -versions option ignored outside of -dependents mode\n");
300 if ( (options
.mode
== modeDependencies
) && (options
.dependentsOfPath
== NULL
) ) {
301 fprintf(stderr
, "Error: -dependents given, but no dylib path specified\n");
307 const DyldSharedCache
* dyldCache
= nullptr;
308 if ( sharedCachePath
!= nullptr ) {
309 dyldCache
= mapCacheFile(sharedCachePath
);
310 // mapCacheFile prints an error if something goes wrong, so just return in that case.
311 if ( dyldCache
== nullptr )
315 #if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)
317 dyldCache
= (DyldSharedCache
*)_dyld_get_shared_cache_range(&cacheLength
);
319 if (dyldCache
== nullptr) {
320 fprintf(stderr
, "Could not get in-memory shared cache\n");
325 if ( options
.mode
== modeSlideInfo
|| options
.mode
== modeVerboseSlideInfo
) {
326 const dyld_cache_header
* header
= &dyldCache
->header
;
327 if ( header
->slideInfoOffset
== 0 ) {
328 fprintf(stderr
, "Error: dyld shared cache does not contain slide info\n");
331 const dyld_cache_mapping_info
* mappings
= (const dyld_cache_mapping_info
*)((char*)dyldCache
+ header
->mappingOffset
);
332 const dyld_cache_mapping_info
* dataMapping
= &mappings
[1];
333 uint64_t dataStartAddress
= dataMapping
->address
;
334 uint64_t dataSize
= dataMapping
->size
;
336 const dyld_cache_slide_info
* slideInfoHeader
= dyldCache
->slideInfo();
337 printf("slide info version=%d\n", slideInfoHeader
->version
);
338 if ( slideInfoHeader
->version
== 1 ) {
339 printf("toc_count=%d, data page count=%lld\n", slideInfoHeader
->toc_count
, dataSize
/4096);
340 const dyld_cache_slide_info_entry
* entries
= (dyld_cache_slide_info_entry
*)((char*)slideInfoHeader
+ slideInfoHeader
->entries_offset
);
341 const uint16_t* tocs
= (uint16_t*)((char*)slideInfoHeader
+ slideInfoHeader
->toc_offset
);
342 for(int i
=0; i
< slideInfoHeader
->toc_count
; ++i
) {
343 printf("0x%08llX: [% 5d,% 5d] ", dataStartAddress
+ i
*4096, i
, tocs
[i
]);
344 const dyld_cache_slide_info_entry
* entry
= &entries
[tocs
[i
]];
345 for(int j
=0; j
< slideInfoHeader
->entries_size
; ++j
)
346 printf("%02X", entry
->bits
[j
]);
350 else if ( slideInfoHeader
->version
== 2 ) {
351 const dyld_cache_slide_info2
* slideInfo
= (dyld_cache_slide_info2
*)(slideInfoHeader
);
352 printf("page_size=%d\n", slideInfo
->page_size
);
353 printf("delta_mask=0x%016llX\n", slideInfo
->delta_mask
);
354 printf("value_add=0x%016llX\n", slideInfo
->value_add
);
355 printf("page_starts_count=%d, page_extras_count=%d\n", slideInfo
->page_starts_count
, slideInfo
->page_extras_count
);
356 const uint16_t* starts
= (uint16_t* )((char*)slideInfo
+ slideInfo
->page_starts_offset
);
357 const uint16_t* extras
= (uint16_t* )((char*)slideInfo
+ slideInfo
->page_extras_offset
);
358 for (int i
=0; i
< slideInfo
->page_starts_count
; ++i
) {
359 const uint16_t start
= starts
[i
];
360 auto rebaseChain
= [&](uint8_t* pageContent
, uint16_t startOffset
)
362 uintptr_t slideAmount
= 0;
363 const uintptr_t deltaMask
= (uintptr_t)(slideInfo
->delta_mask
);
364 const uintptr_t valueMask
= ~deltaMask
;
365 const uintptr_t valueAdd
= (uintptr_t)(slideInfo
->value_add
);
366 const unsigned deltaShift
= __builtin_ctzll(deltaMask
) - 2;
368 uint32_t pageOffset
= startOffset
;
370 while ( delta
!= 0 ) {
371 uint8_t* loc
= pageContent
+ pageOffset
;
372 uintptr_t rawValue
= *((uintptr_t*)loc
);
373 delta
= (uint32_t)((rawValue
& deltaMask
) >> deltaShift
);
374 uintptr_t value
= (rawValue
& valueMask
);
377 value
+= slideAmount
;
379 printf(" [% 5d + 0x%04llX]: 0x%016llX = 0x%016llX\n", i
, (uint64_t)(pageOffset
), (uint64_t)rawValue
, (uint64_t)value
);
383 const uint8_t* dataPagesStart
= dyldCache
->dataRegionStart();
384 if ( start
== DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE
) {
385 printf("page[% 5d]: no rebasing\n", i
);
387 else if ( start
& DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA
) {
388 printf("page[% 5d]: ", i
);
389 int j
=(start
& 0x3FFF);
392 uint16_t aStart
= extras
[j
];
393 printf("start=0x%04X ", aStart
& 0x3FFF);
394 if ( options
.mode
== modeVerboseSlideInfo
) {
395 uint8_t* page
= (uint8_t*)(long)(dataPagesStart
+ (slideInfo
->page_size
*i
));
396 uint16_t pageStartOffset
= (aStart
& 0x3FFF)*4;
397 rebaseChain(page
, pageStartOffset
);
399 done
= (extras
[j
] & DYLD_CACHE_SLIDE_PAGE_ATTR_END
);
405 printf("page[% 5d]: start=0x%04X\n", i
, starts
[i
]);
406 if ( options
.mode
== modeVerboseSlideInfo
) {
407 uint8_t* page
= (uint8_t*)(long)(dataPagesStart
+ (slideInfo
->page_size
*i
));
408 uint16_t pageStartOffset
= start
*4;
409 rebaseChain(page
, pageStartOffset
);
414 else if ( slideInfoHeader
->version
== 3 ) {
415 const dyld_cache_slide_info3
* slideInfo
= (dyld_cache_slide_info3
*)(slideInfoHeader
);
416 printf("page_size=%d\n", slideInfo
->page_size
);
417 printf("page_starts_count=%d\n", slideInfo
->page_starts_count
);
418 printf("auth_value_add=0x%016llX\n", slideInfo
->auth_value_add
);
419 const uintptr_t authValueAdd
= (uintptr_t)(slideInfo
->auth_value_add
);
420 const uint8_t* dataSegmentStart
= dyldCache
->dataRegionStart();
421 for (int i
=0; i
< slideInfo
->page_starts_count
; ++i
) {
422 uint16_t delta
= slideInfo
->page_starts
[i
];
423 if ( delta
== DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE
) {
424 printf("page[% 5d]: no rebasing\n", i
);
428 printf("page[% 5d]: start=0x%04X\n", i
, delta
);
429 if ( options
.mode
!= modeVerboseSlideInfo
)
432 delta
= delta
/sizeof(uint64_t); // initial offset is byte based
433 const uint8_t* pageStart
= dataSegmentStart
+ (i
* slideInfo
->page_size
);
434 const dyld_cache_slide_pointer3
* loc
= (dyld_cache_slide_pointer3
*)pageStart
;
437 delta
= loc
->plain
.offsetToNextPointer
;
438 dyld3::MachOLoaded::ChainedFixupPointerOnDisk ptr
;
439 ptr
.raw64
= *((uint64_t*)loc
);
440 if ( loc
->auth
.authenticated
) {
441 uint64_t target
= authValueAdd
+ loc
->auth
.offsetFromSharedCacheBase
;
442 uint64_t targetValue
= ptr
.arm64e
.signPointer((void*)loc
, target
);
443 printf(" [% 5d + 0x%04llX]: 0x%016llX (JOP: diversity %d, address %s, %s)\n",
444 i
, (uint64_t)((const uint8_t*)loc
- pageStart
), targetValue
,
445 ptr
.arm64e
.authBind
.diversity
, ptr
.arm64e
.authBind
.addrDiv
? "true" : "false",
446 ptr
.arm64e
.keyName());
449 uint64_t targetValue
= ptr
.arm64e
.unpackTarget();
450 printf(" [% 5d + 0x%04llX]: 0x%016llX\n", i
, (uint64_t)((const uint8_t*)loc
- pageStart
), targetValue
);
452 } while (delta
!= 0);
455 else if ( slideInfoHeader
->version
== 4 ) {
456 const dyld_cache_slide_info4
* slideInfo
= (dyld_cache_slide_info4
*)(slideInfoHeader
);
457 printf("page_size=%d\n", slideInfo
->page_size
);
458 printf("delta_mask=0x%016llX\n", slideInfo
->delta_mask
);
459 printf("value_add=0x%016llX\n", slideInfo
->value_add
);
460 printf("page_starts_count=%d, page_extras_count=%d\n", slideInfo
->page_starts_count
, slideInfo
->page_extras_count
);
461 const uint16_t* starts
= (uint16_t* )((char*)slideInfo
+ slideInfo
->page_starts_offset
);
462 const uint16_t* extras
= (uint16_t* )((char*)slideInfo
+ slideInfo
->page_extras_offset
);
463 for (int i
=0; i
< slideInfo
->page_starts_count
; ++i
) {
464 const uint16_t start
= starts
[i
];
465 auto rebaseChainV4
= [&](uint8_t* pageContent
, uint16_t startOffset
)
467 uintptr_t slideAmount
= 0;
468 const uintptr_t deltaMask
= (uintptr_t)(slideInfo
->delta_mask
);
469 const uintptr_t valueMask
= ~deltaMask
;
470 const uintptr_t valueAdd
= (uintptr_t)(slideInfo
->value_add
);
471 const unsigned deltaShift
= __builtin_ctzll(deltaMask
) - 2;
473 uint32_t pageOffset
= startOffset
;
475 while ( delta
!= 0 ) {
476 uint8_t* loc
= pageContent
+ pageOffset
;
477 uint32_t rawValue
= *((uint32_t*)loc
);
478 delta
= (uint32_t)((rawValue
& deltaMask
) >> deltaShift
);
479 uintptr_t value
= (rawValue
& valueMask
);
480 if ( (value
& 0xFFFF8000) == 0 ) {
481 // small positive non-pointer, use as-is
483 else if ( (value
& 0x3FFF8000) == 0x3FFF8000 ) {
484 // small negative non-pointer
489 value
+= slideAmount
;
491 printf(" [% 5d + 0x%04X]: 0x%08X\n", i
, pageOffset
, rawValue
);
495 const uint8_t* dataPagesStart
= dyldCache
->dataRegionStart();
496 if ( start
== DYLD_CACHE_SLIDE4_PAGE_NO_REBASE
) {
497 printf("page[% 5d]: no rebasing\n", i
);
499 else if ( start
& DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA
) {
500 printf("page[% 5d]: ", i
);
501 int j
=(start
& DYLD_CACHE_SLIDE4_PAGE_INDEX
);
504 uint16_t aStart
= extras
[j
];
505 printf("start=0x%04X ", aStart
& DYLD_CACHE_SLIDE4_PAGE_INDEX
);
506 if ( options
.mode
== modeVerboseSlideInfo
) {
507 uint8_t* page
= (uint8_t*)(long)(dataPagesStart
+ (slideInfo
->page_size
*i
));
508 uint16_t pageStartOffset
= (aStart
& DYLD_CACHE_SLIDE4_PAGE_INDEX
)*4;
509 rebaseChainV4(page
, pageStartOffset
);
511 done
= (extras
[j
] & DYLD_CACHE_SLIDE4_PAGE_EXTRA_END
);
517 printf("page[% 5d]: start=0x%04X\n", i
, starts
[i
]);
518 if ( options
.mode
== modeVerboseSlideInfo
) {
519 uint8_t* page
= (uint8_t*)(long)(dataPagesStart
+ (slideInfo
->page_size
*i
));
520 uint16_t pageStartOffset
= start
*4;
521 rebaseChainV4(page
, pageStartOffset
);
527 else if ( options
.mode
== modeInfo
) {
528 const dyld_cache_header
* header
= &dyldCache
->header
;
530 if ( header
->mappingOffset
>= 0x68 ) {
531 const uint8_t* uuid
= header
->uuid
;
532 printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
533 uuid
[0], uuid
[1], uuid
[2], uuid
[3],
534 uuid
[4], uuid
[5], uuid
[6], uuid
[7],
535 uuid
[8], uuid
[9], uuid
[10], uuid
[11],
536 uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
541 if ( header
->mappingOffset
>= 0xE0 ) {
542 // HACK until this uses new header
543 uint32_t platform
= *((uint32_t*)(((char*)header
) + 0xD8));
544 uint32_t bitfield
= *((uint32_t*)(((char*)header
) + 0xDC));
545 uint32_t simulator
= bitfield
& 0x200;
546 uint32_t locallyBuiltCache
= bitfield
& 0x400;
549 printf("platform: macOS\n");
553 printf("platform: iOS simulator\n");
555 printf("platform: iOS\n");
559 printf("platform: tvOS simulator\n");
561 printf("platform: tvOS\n");
565 printf("platform: watchOS simulator\n");
567 printf("platform: watchOS\n");
570 printf("platform: bridgeOS\n");
573 printf("platform: 0x%08X 0x%08X\n", platform
, simulator
);
575 printf("built by: %s\n", locallyBuiltCache
? "local machine" : "B&I");
577 printf("cache type: %s\n", header
->cacheType
? "production" : "development");
578 printf("image count: %u\n", header
->imagesCount
);
579 if ( (header
->mappingOffset
>= 0x78) && (header
->branchPoolsOffset
!= 0) ) {
580 printf("branch pool count: %u\n", header
->branchPoolsCount
);
582 if ( header
->slideInfoSize
> 0 ) {
583 uint32_t pageSize
= 0x4000; // fix me for intel
584 uint32_t possibleSlideValues
= (uint32_t)(header
->maxSlide
/pageSize
);
585 uint32_t entropyBits
= 32 - __builtin_clz(possibleSlideValues
- 1);
586 printf("ASLR entropy: %u-bits\n", entropyBits
);
588 printf("mappings:\n");
589 const dyld_cache_mapping_info
* mappings
= (const dyld_cache_mapping_info
*)((char*)dyldCache
+ header
->mappingOffset
);
590 for (uint32_t i
=0; i
< header
->mappingCount
; ++i
) {
591 if ( mappings
[i
].initProt
& VM_PROT_EXECUTE
)
592 printf(" __TEXT %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
593 mappings
[i
].size
/(1024*1024), mappings
[i
].fileOffset
, mappings
[i
].fileOffset
+ mappings
[i
].size
,
594 mappings
[i
].address
, mappings
[i
].address
+ mappings
[i
].size
);
595 else if ( mappings
[i
].initProt
& VM_PROT_WRITE
)
596 printf(" __DATA %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
597 mappings
[i
].size
/(1024*1024), mappings
[i
].fileOffset
, mappings
[i
].fileOffset
+ mappings
[i
].size
,
598 mappings
[i
].address
, mappings
[i
].address
+ mappings
[i
].size
);
599 else if ( mappings
[i
].initProt
& VM_PROT_READ
)
600 printf(" __LINKEDIT %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
601 mappings
[i
].size
/(1024*1024), mappings
[i
].fileOffset
, mappings
[i
].fileOffset
+ mappings
[i
].size
,
602 mappings
[i
].address
, mappings
[i
].address
+ mappings
[i
].size
);
604 if ( header
->codeSignatureOffset
!= 0 ) {
605 uint64_t size
= header
->codeSignatureSize
;
606 uint64_t csAddr
= mappings
[header
->mappingCount
-1].address
+ mappings
[header
->mappingCount
-1].size
;
608 printf(" code sign %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
609 size
/(1024*1024), header
->codeSignatureOffset
, header
->codeSignatureOffset
+ size
, csAddr
, csAddr
+ size
);
611 printf("slide info: %4lluKB, file offset: 0x%08llX -> 0x%08llX\n",
612 header
->slideInfoSize
/1024, header
->slideInfoOffset
, header
->slideInfoOffset
+ header
->slideInfoSize
);
613 if ( header
->localSymbolsOffset
!= 0 )
614 printf("local symbols: %3lluMB, file offset: 0x%08llX -> 0x%08llX\n",
615 header
->localSymbolsSize
/(1024*1024), header
->localSymbolsOffset
, header
->localSymbolsOffset
+ header
->localSymbolsSize
);
616 if ( (header
->mappingOffset
>= 0x78) && (header
->accelerateInfoSize
!= 0) )
617 printf("accelerate tab: %3lluKB, address: 0x%08llX -> 0x%08llX\n",
618 header
->accelerateInfoSize
/1024, header
->accelerateInfoAddr
, header
->accelerateInfoAddr
+ header
->accelerateInfoSize
);
620 else if ( options
.mode
== modeAcceleratorInfo
) {
621 const dyld_cache_header
* header
= &dyldCache
->header
;
622 if ( (header
->mappingOffset
< sizeof(dyld_cache_header
)) || (header
->accelerateInfoSize
== 0) ) {
623 printf("no accelerator info\n");
626 const dyld_cache_mapping_info
* mappings
= (const dyld_cache_mapping_info
*)((char*)dyldCache
+ header
->mappingOffset
);
627 uint64_t aiAddr
= header
->accelerateInfoAddr
;
628 const dyld_cache_accelerator_info
* accelInfo
= NULL
;
629 for (uint32_t i
=0; i
< header
->mappingCount
; ++i
) {
630 if ( (mappings
[i
].address
<= aiAddr
) && (aiAddr
< mappings
[i
].address
+mappings
[i
].size
) ) {
631 uint64_t offset
= aiAddr
- mappings
[i
].address
+ mappings
[i
].fileOffset
;
632 accelInfo
= (dyld_cache_accelerator_info
*)((uint8_t*)dyldCache
+ offset
);
635 if ( accelInfo
== NULL
) {
636 printf("accelerator info not in any mapped range\n");
639 const dyld_cache_image_info
* images
= (dyld_cache_image_info
*)((char*)dyldCache
+ header
->imagesOffset
);
640 const dyld_cache_image_info_extra
* imagesExtra
= (dyld_cache_image_info_extra
*)((char*)accelInfo
+ accelInfo
->imagesExtrasOffset
);
641 const uint16_t* dependencyArray
= (uint16_t*)((char*)accelInfo
+ accelInfo
->depListOffset
);
642 const uint16_t* reExportArray
= (uint16_t*)((char*)accelInfo
+ accelInfo
->reExportListOffset
);
643 printf("extra image info (count=%u):\n", accelInfo
->imageExtrasCount
);
644 for (uint32_t i
=0; i
< accelInfo
->imageExtrasCount
; ++i
) {
645 printf(" image[%3u] %s:\n", i
, (char*)dyldCache
+images
[i
].pathFileOffset
);
646 printf(" exports trie: addr=0x%llX, size=0x%08X\n", imagesExtra
[i
].exportsTrieAddr
, imagesExtra
[i
].exportsTrieSize
);
647 if ( imagesExtra
[i
].weakBindingsSize
)
648 printf(" weak bind info: addr=0x%llX, size=0x%08X\n", imagesExtra
[i
].weakBindingsAddr
, imagesExtra
[i
].weakBindingsSize
);
649 printf(" dependents: ");
650 for (uint32_t d
=imagesExtra
[i
].dependentsStartArrayIndex
; dependencyArray
[d
] != 0xFFFF; ++d
) {
651 uint16_t depIndex
= dependencyArray
[d
];
652 if ( depIndex
& 0x8000 )
653 printf(" up(%d) ", depIndex
& 0x7FFF);
655 printf(" %d ", depIndex
);
658 printf(" re-exports: ");
659 for (uint32_t r
=imagesExtra
[i
].reExportsStartArrayIndex
; reExportArray
[r
] != 0xFFFF; ++r
)
660 printf(" %d ", reExportArray
[r
]);
663 printf("libdyld.dylib:\n");
664 printf(" __dyld section address: 0x%llX\n", accelInfo
->dyldSectionAddr
);
665 printf("initializers (count=%u):\n", accelInfo
->initializersCount
);
666 const dyld_cache_accelerator_initializer
* initializers
= (dyld_cache_accelerator_initializer
*)((char*)accelInfo
+ accelInfo
->initializersOffset
);
667 for (uint32_t i
=0; i
< accelInfo
->initializersCount
; ++i
) {
668 printf(" image[%3u] 0x%llX\n", initializers
[i
].imageIndex
, mappings
[0].address
+ initializers
[i
].functionOffset
);
670 printf("DOF sections (count=%u):\n", accelInfo
->dofSectionsCount
);
671 const dyld_cache_accelerator_dof
* dofs
= (dyld_cache_accelerator_dof
*)((char*)accelInfo
+ accelInfo
->dofSectionsOffset
);
672 for (uint32_t i
=0; i
< accelInfo
->dofSectionsCount
; ++i
) {
673 printf(" image[%3u] 0x%llX -> 0x%llX\n", dofs
[i
].imageIndex
, dofs
[i
].sectionAddress
, dofs
[i
].sectionAddress
+dofs
[i
].sectionSize
);
675 printf("bottom up order (count=%u):\n", accelInfo
->imageExtrasCount
);
676 const uint16_t* bottomUpArray
= (uint16_t*)((char*)accelInfo
+ accelInfo
->bottomUpListOffset
);
677 for (uint32_t i
=0; i
< accelInfo
->imageExtrasCount
; ++i
) {
678 unsigned imageIndex
= bottomUpArray
[i
];
679 if ( imageIndex
< accelInfo
->imageExtrasCount
)
680 printf(" image[%3u] %s\n", imageIndex
, (char*)dyldCache
+ images
[imageIndex
].pathFileOffset
);
682 printf(" image[%3u] BAD INDEX\n", imageIndex
);
684 printf("range table (count=%u):\n", accelInfo
->rangeTableCount
);
685 const dyld_cache_range_entry
* rangeTable
= (dyld_cache_range_entry
*)((char*)accelInfo
+ accelInfo
->rangeTableOffset
);
686 for (uint32_t i
=0; i
< accelInfo
->rangeTableCount
; ++i
) {
687 const dyld_cache_range_entry
& entry
= rangeTable
[i
];
688 printf(" 0x%llX -> 0x%llX %s\n", entry
.startAddress
, entry
.startAddress
+ entry
.size
, (char*)dyldCache
+ images
[entry
.imageIndex
].pathFileOffset
);
690 printf("dylib trie (size=%u):\n", accelInfo
->dylibTrieSize
);
691 const uint8_t* dylibTrieStart
= (uint8_t*)accelInfo
+ accelInfo
->dylibTrieOffset
;
692 const uint8_t* dylibTrieEnd
= dylibTrieStart
+ accelInfo
->dylibTrieSize
;
693 std::vector
<DylibIndexTrie::Entry
> dylibEntries
;
694 if ( !Trie
<DylibIndex
>::parseTrie(dylibTrieStart
, dylibTrieEnd
, dylibEntries
) )
695 printf(" malformed dylibs trie\n");
696 for (const DylibIndexTrie::Entry
& x
: dylibEntries
) {
697 printf(" image[%3u] %s\n", x
.info
.index
, x
.name
.c_str());
702 else if ( options
.mode
== modeTextInfo
) {
703 const dyld_cache_header
* header
= &dyldCache
->header
;
704 if ( (header
->mappingOffset
< sizeof(dyld_cache_header
)) || (header
->imagesTextCount
== 0) ) {
705 printf("no text info\n");
708 const dyld_cache_image_text_info
* imagesText
= (dyld_cache_image_text_info
*)((char*)dyldCache
+ header
->imagesTextOffset
);
709 const dyld_cache_image_text_info
* imagesTextEnd
= &imagesText
[header
->imagesTextCount
];
710 printf("dylib text infos (count=%llu):\n", header
->imagesTextCount
);
711 for (const dyld_cache_image_text_info
* p
=imagesText
; p
< imagesTextEnd
; ++p
) {
712 printf(" 0x%09llX -> 0x%09llX <", p
->loadAddress
, p
->loadAddress
+ p
->textSegmentSize
);
713 for (int i
=0; i
<16; ++i
) {
722 printf("%02X", p
->uuid
[i
]);
724 printf("> %s\n", (char*)dyldCache
+ p
->pathOffset
);
728 else if ( options
.mode
== modeLocalSymbols
) {
729 const dyld_cache_header
* header
= &dyldCache
->header
;
730 if ( header
->localSymbolsOffset
== 0 ) {
731 fprintf(stderr
, "Error: dyld shared cache does not contain local symbols info\n");
734 const bool is64
= (strstr((char*)dyldCache
, "64") != NULL
);
735 const dyld_cache_image_info
* imageInfos
= (dyld_cache_image_info
*)((char*)dyldCache
+ header
->imagesOffset
);
736 const dyld_cache_local_symbols_info
* localsInfo
= (dyld_cache_local_symbols_info
*)((char*)dyldCache
+ header
->localSymbolsOffset
);
737 const uint32_t nlistFileOffset
= (uint32_t)(header
->localSymbolsOffset
+ localsInfo
->nlistOffset
);
738 const uint32_t nlistCount
= localsInfo
->nlistCount
;
739 const uint32_t nlistByteSize
= is64
? nlistCount
*16 : nlistCount
*12;
740 const uint32_t stringsFileOffset
= (uint32_t)(header
->localSymbolsOffset
+ localsInfo
->stringsOffset
);
741 const uint32_t stringsSize
= localsInfo
->stringsSize
;
742 const uint32_t entriesCount
= localsInfo
->entriesCount
;
743 const dyld_cache_local_symbols_entry
* entries
= (dyld_cache_local_symbols_entry
*)((char*)localsInfo
+ localsInfo
->entriesOffset
);
744 printf("local symbols nlist array: %3uMB, file offset: 0x%08X -> 0x%08X\n", nlistByteSize
/(1024*1024), nlistFileOffset
, nlistFileOffset
+nlistByteSize
);
745 printf("local symbols string pool: %3uMB, file offset: 0x%08X -> 0x%08X\n", stringsSize
/(1024*1024), stringsFileOffset
, stringsFileOffset
+stringsSize
);
746 printf("local symbols by dylib (count=%d):\n", entriesCount
);
747 //const char* stringPool = (char*)dyldCache + stringsFileOffset;
748 for (int i
=0; i
< entriesCount
; ++i
) {
749 const char* imageName
= (char*)dyldCache
+ imageInfos
[i
].pathFileOffset
;
750 printf(" nlistStartIndex=%5d, nlistCount=%5d, image=%s\n", entries
[i
].nlistStartIndex
, entries
[i
].nlistCount
, imageName
);
753 const nlist_64
* symTab
= (nlist_64
*)((char*)dyldCache
+ nlistFileOffset
);
754 for (int e
=0; e
< entries
[i
].nlistCount(); ++e
) {
755 const nlist_64
* entry
= &symTab
[entries
[i
].nlistStartIndex()+e
];
756 printf(" nlist[%d].str=%d, %s\n", e
, entry
->n_un
.n_strx
, &stringPool
[entry
->n_un
.n_strx
]);
757 printf(" nlist[%d].value=0x%0llX\n", e
, entry
->n_value
);
763 else if ( options
.mode
== modeJSONMap
) {
764 std::string buffer
= dyldCache
->generateJSONMap("unknown");
765 printf("%s\n", buffer
.c_str());
767 else if ( options
.mode
== modeJSONDependents
) {
768 std::cout
<< dyldCache
->generateJSONDependents();
770 else if ( options
.mode
== modeStrings
) {
772 dyldCache
->forEachImage(^(const mach_header
*mh
, const char *installName
) {
773 const dyld3::MachOAnalyzer
* ma
= (dyld3::MachOAnalyzer
*)mh
;
774 int64_t slide
= ma
->getSlide();
775 ma
->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo
& info
, bool malformedSectionRange
, bool& stop
) {
776 if ( ( (info
.sectFlags
& SECTION_TYPE
) == S_CSTRING_LITERALS
) ) {
777 if ( malformedSectionRange
) {
781 const uint8_t* content
= (uint8_t*)(info
.sectAddr
+ slide
);
782 const char* s
= (char*)content
;
783 const char* end
= s
+ info
.sectSize
;
785 printf("%s: %s\n", ma
->installName(), s
);
796 dyldCache
->forEachImage(^(const mach_header
*mh
, const char *installName
) {
797 const dyld3::MachOAnalyzer
* ma
= (dyld3::MachOAnalyzer
*)mh
;
798 uint32_t exportTrieRuntimeOffset
;
799 uint32_t exportTrieSize
;
800 if ( ma
->hasExportTrie(exportTrieRuntimeOffset
, exportTrieSize
) ) {
801 const uint8_t* start
= (uint8_t*)mh
+ exportTrieRuntimeOffset
;
802 const uint8_t* end
= start
+ exportTrieSize
;
803 std::vector
<ExportInfoTrie::Entry
> exports
;
804 if ( !ExportInfoTrie::parseTrie(start
, end
, exports
) ) {
808 for (const ExportInfoTrie::Entry
& entry
: exports
) {
809 printf("%s: %s\n", ma
->installName(), entry
.name
.c_str());
815 else if ( options
.mode
== modeSectionSizes
) {
816 __block
std::map
<std::string
, uint64_t> sectionSizes
;
817 dyldCache
->forEachImage(^(const mach_header
*mh
, const char *installName
) {
818 const dyld3::MachOAnalyzer
* ma
= (const dyld3::MachOAnalyzer
*)mh
;
819 ma
->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo
§Info
, bool malformedSectionRange
, bool &stop
) {
820 std::string section
= std::string(sectInfo
.segInfo
.segName
) + " " + sectInfo
.sectName
;
821 sectionSizes
[section
] += sectInfo
.sectSize
;
824 for (const auto& keyAndValue
: sectionSizes
) {
825 printf("%lld %s\n", keyAndValue
.second
, keyAndValue
.first
.c_str());
828 else if ( options
.mode
== modeObjCProtocols
) {
829 if ( dyldCache
->objcOpt() == nullptr ) {
830 fprintf(stderr
, "Error: could not get optimized objc\n");
833 objc_opt::objc_protocolopt2_t
* protocols
= dyldCache
->objcOpt()->protocolopt2();
834 if ( protocols
== nullptr ) {
835 fprintf(stderr
, "Error: could not get optimized objc protocols\n");
839 for (uint64_t index
= 0; index
!= protocols
->capacity
; ++index
) {
840 const objc_opt::objc_classheader_t
& clshi
= protocols
->classOffsets()[index
];
841 if ( clshi
.clsOffset
== 0 ) {
842 fprintf(stderr
, "[% 5lld]\n", index
);
845 const char* name
= (const char*)(((const uint8_t*)protocols
) + protocols
->offsets()[index
]);
846 if ( !clshi
.isDuplicate() ) {
847 fprintf(stderr
, "[% 5lld] -> (% 8d, % 8d) = %s\n", index
, clshi
.clsOffset
, clshi
.hiOffset
, name
);
851 // class appears in more than one header
852 uint32_t count
= clshi
.duplicateCount();
853 fprintf(stderr
, "[% 5lld] -> duplicates [% 5d..% 5d] = %s\n",
854 index
, clshi
.duplicateIndex(), clshi
.duplicateIndex() + clshi
.duplicateCount() - 1, name
);
856 const objc_opt::objc_classheader_t
*list
= &protocols
->duplicateOffsets()[clshi
.duplicateIndex()];
857 for (uint32_t i
= 0; i
< count
; i
++) {
858 fprintf(stderr
, " - [% 5lld] -> (% 8d, % 8d)\n", (uint64_t)(clshi
.duplicateIndex() + i
), list
[i
].clsOffset
, list
[i
].hiOffset
);
862 else if ( options
.mode
== modeExtract
) {
863 char pathBuffer
[PATH_MAX
];
864 uint32_t bufferSize
= PATH_MAX
;
865 if ( _NSGetExecutablePath(pathBuffer
, &bufferSize
) != 0 ) {
866 fprintf(stderr
, "Error: could not get path of program\n");
869 char* last
= strrchr(pathBuffer
, '/');
870 // The bundle is at a different location on device. Its /usr/lib/dsc_extractor.bundle in the SDK
871 // but /usr/local/lib/dsc_extractor.bundle on device.
872 strcpy(last
+1, DSC_BUNDLE_REL_PATH
);
873 void* handle
= dlopen(pathBuffer
, RTLD_LAZY
);
874 if ( handle
== NULL
) {
875 fprintf(stderr
, "Error: dsc_extractor.bundle could not be loaded at %s\n", pathBuffer
);
879 typedef int (*extractor_proc
)(const char* shared_cache_file_path
, const char* extraction_root_path
,
880 void (^progress
)(unsigned current
, unsigned total
));
882 extractor_proc proc
= (extractor_proc
)dlsym(handle
, "dyld_shared_cache_extract_dylibs_progress");
883 if ( proc
== NULL
) {
884 fprintf(stderr
, "Error: dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
888 int result
= (*proc
)(sharedCachePath
, options
.extractionDir
, ^(unsigned c
, unsigned total
) { } );
892 switch ( options
.mode
) {
894 if (options
.printInodes
) {
895 dyldCache
->forEachImageEntry(^(const char* path
, uint64_t mTime
, uint64_t inode
) {
896 printf("0x%08llX 0x%08llX ", inode
, mTime
);
897 if ( isAlias(path
, dyldCache
) )
898 printf("[alias] %s\n", path
);
900 printf("%s\n", path
);
903 dyldCache
->forEachImageTextSegment(^(uint64_t loadAddressUnslid
, uint64_t textSegmentSize
, const unsigned char *dylibUUID
, const char *installName
, bool &stop
) {
904 if ( options
.printVMAddrs
)
905 printf("0x%08llX ", loadAddressUnslid
);
906 if ( options
.printUUIDs
) {
907 const uint8_t* uuid
= (uint8_t*)dylibUUID
;
908 printf("<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X> ",
909 uuid
[0], uuid
[1], uuid
[2], uuid
[3],
910 uuid
[4], uuid
[5], uuid
[6], uuid
[7],
911 uuid
[8], uuid
[9], uuid
[10], uuid
[11],
912 uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
914 if ( isAlias(installName
, dyldCache
) )
915 printf("[alias] %s\n", installName
);
917 printf("%s\n", installName
);
923 __block
std::map
<uint64_t, const char*> dataSegNames
;
924 __block
std::map
<uint64_t, uint64_t> dataSegEnds
;
925 dyldCache
->forEachImage(^(const mach_header
* mh
, const char* installName
) {
926 dyld3::MachOFile
* mf
= (dyld3::MachOFile
*)mh
;
927 mf
->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo
&info
, bool &stop
) {
928 if ( isAlias(installName
, dyldCache
) )
930 printf("0x%08llX - 0x%08llX %s %s\n", info
.vmAddr
, info
.vmAddr
+ info
.vmSize
, info
.segName
, installName
);
931 if ( strncmp(info
.segName
, "__DATA", 6) == 0 ) {
932 dataSegNames
[info
.vmAddr
] = installName
;
933 dataSegEnds
[info
.vmAddr
] = info
.vmAddr
+ info
.vmSize
;
937 // <rdar://problem/51084507> Enhance dyld_shared_cache_util to show where section alignment added padding
938 uint64_t lastEnd
= 0;
939 for (const auto& entry
: dataSegEnds
) {
940 uint64_t padding
= entry
.first
- lastEnd
;
941 if ( (padding
> 32) && (lastEnd
!= 0) ) {
942 printf("0x%08llX - 0x%08llX PADDING %lluKB\n", lastEnd
, entry
.first
, padding
/1024);
944 lastEnd
= entry
.second
;
948 case modeDependencies
: {
949 __block
bool dependentTargetFound
= false;
950 dyldCache
->forEachImage(^(const mach_header
* mh
, const char* installName
) {
951 if ( strcmp(options
.dependentsOfPath
, installName
) != 0 )
953 dependentTargetFound
= true;
955 auto printDep
= [&options
](const char *loadPath
, uint32_t compatVersion
, uint32_t curVersion
) {
956 if ( options
.printDylibVersions
) {
957 uint32_t compat_vers
= compatVersion
;
958 uint32_t current_vers
= curVersion
;
959 printf("\t%s", loadPath
);
960 if ( compat_vers
!= 0xFFFFFFFF ) {
961 printf("(compatibility version %u.%u.%u, current version %u.%u.%u)\n",
963 (compat_vers
>> 8) & 0xff,
964 (compat_vers
) & 0xff,
965 (current_vers
>> 16),
966 (current_vers
>> 8) & 0xff,
967 (current_vers
) & 0xff);
974 printf("\t%s\n", loadPath
);
978 dyld3::MachOFile
* mf
= (dyld3::MachOFile
*)mh
;
980 // First print out our dylib and version.
981 const char* dylibInstallName
;
982 uint32_t currentVersion
;
983 uint32_t compatVersion
;
984 if ( mf
->getDylibInstallName(&dylibInstallName
, &compatVersion
, ¤tVersion
) ) {
985 printDep(dylibInstallName
, compatVersion
, currentVersion
);
988 // Then the dependent dylibs.
989 mf
->forEachDependentDylib(^(const char *loadPath
, bool isWeak
, bool isReExport
, bool isUpward
, uint32_t compatVersion
, uint32_t curVersion
, bool &stop
) {
990 printDep(loadPath
, compatVersion
, curVersion
);
993 if (options
.dependentsOfPath
&& !dependentTargetFound
) {
994 fprintf(stderr
, "Error: could not find '%s' in the shared cache at\n %s\n", options
.dependentsOfPath
, sharedCachePath
);
1000 std::map
<uint32_t, const char*> pageToContent
;
1001 auto add_linkedit
= [&pageToContent
](uint32_t pageStart
, uint32_t pageEnd
, const char* message
) {
1002 for (uint32_t p
= pageStart
; p
<= pageEnd
; p
+= 4096) {
1003 std::map
<uint32_t, const char*>::iterator pos
= pageToContent
.find(p
);
1004 if ( pos
== pageToContent
.end() ) {
1005 pageToContent
[p
] = strdup(message
);
1008 const char* oldMessage
= pos
->second
;
1010 asprintf(&newMesssage
, "%s, %s", oldMessage
, message
);
1011 pageToContent
[p
] = newMesssage
;
1012 ::free((void*)oldMessage
);
1017 dyldCache
->forEachImage(^(const mach_header
* mh
, const char* installName
) {
1018 // Filter out symlinks.
1019 if (isAlias(installName
, dyldCache
))
1021 dyld3::MachOAnalyzer
* ma
= (dyld3::MachOAnalyzer
*)mh
;
1023 dyld3::MachOAnalyzer::LinkEditInfo leInfo
;
1024 ma
->getLinkEditPointers(diag
, leInfo
);
1026 if (diag
.hasError())
1030 const char* shortName
= strrchr(installName
, '/') + 1;
1031 // add export trie info
1032 if ( leInfo
.dyldInfo
->export_size
!= 0 ) {
1033 //printf("export_off=0x%X\n", leInfo.dyldInfo->export_off());
1034 uint32_t exportPageOffsetStart
= leInfo
.dyldInfo
->export_off
& (-4096);
1035 uint32_t exportPageOffsetEnd
= (leInfo
.dyldInfo
->export_off
+ leInfo
.dyldInfo
->export_size
) & (-4096);
1036 sprintf(message
, "exports from %s", shortName
);
1037 add_linkedit(exportPageOffsetStart
, exportPageOffsetEnd
, message
);
1040 if ( leInfo
.dyldInfo
->bind_size
!= 0 ) {
1041 uint32_t bindPageOffsetStart
= leInfo
.dyldInfo
->bind_off
& (-4096);
1042 uint32_t bindPageOffsetEnd
= (leInfo
.dyldInfo
->bind_off
+ leInfo
.dyldInfo
->bind_size
) & (-4096);
1043 sprintf(message
, "bindings from %s", shortName
);
1044 add_linkedit(bindPageOffsetStart
, bindPageOffsetEnd
, message
);
1046 // add lazy binding info
1047 if ( leInfo
.dyldInfo
->lazy_bind_size
!= 0 ) {
1048 uint32_t lazybindPageOffsetStart
= leInfo
.dyldInfo
->lazy_bind_off
& (-4096);
1049 uint32_t lazybindPageOffsetEnd
= (leInfo
.dyldInfo
->lazy_bind_off
+ leInfo
.dyldInfo
->lazy_bind_size
) & (-4096);
1050 sprintf(message
, "lazy bindings from %s", shortName
);
1051 add_linkedit(lazybindPageOffsetStart
, lazybindPageOffsetEnd
, message
);
1053 // add weak binding info
1054 if ( leInfo
.dyldInfo
->weak_bind_size
!= 0 ) {
1055 uint32_t weakbindPageOffsetStart
= leInfo
.dyldInfo
->weak_bind_off
& (-4096);
1056 uint32_t weakbindPageOffsetEnd
= (leInfo
.dyldInfo
->weak_bind_off
+ leInfo
.dyldInfo
->weak_bind_size
) & (-4096);
1057 sprintf(message
, "weak bindings from %s", shortName
);
1058 add_linkedit(weakbindPageOffsetStart
, weakbindPageOffsetEnd
, message
);
1062 for (std::map
<uint32_t, const char*>::iterator it
= pageToContent
.begin(); it
!= pageToContent
.end(); ++it
) {
1063 printf("0x%08X %s\n", it
->first
, it
->second
);
1072 __block
std::vector
<TextInfo
> textSegments
;
1073 dyldCache
->forEachImage(^(const mach_header
* mh
, const char* installName
) {
1074 // Filter out symlinks.
1075 if (isAlias(installName
, dyldCache
))
1078 dyld3::MachOAnalyzer
* ma
= (dyld3::MachOAnalyzer
*)mh
;
1079 ma
->forEachSegment(^(const dyld3::MachOAnalyzer::SegmentInfo
&info
, bool &stop
) {
1080 if ( strcmp(info
.segName
, "__TEXT") != 0 )
1082 textSegments
.push_back({ info
.fileSize
, installName
});
1085 std::sort(textSegments
.begin(), textSegments
.end(), [](const TextInfo
& left
, const TextInfo
& right
) {
1086 return (left
.textSize
> right
.textSize
);
1088 for (std::vector
<TextInfo
>::iterator it
= textSegments
.begin(); it
!= textSegments
.end(); ++it
) {
1089 printf(" 0x%08llX %s\n", it
->textSize
, it
->path
);
1096 case modeVerboseSlideInfo
:
1097 case modeAcceleratorInfo
:
1099 case modeLocalSymbols
:
1101 case modeJSONDependents
:
1102 case modeSectionSizes
:
1104 case modeObjCProtocols
: