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.h>
38 #include <mach-o/dyld_priv.h>
39 #include <mach/mach.h>
44 #include "DyldSharedCache.h"
46 #include "dsc_iterator.h"
47 #include "dsc_extractor.h"
48 #include "dyld_cache_format.h"
49 #include "Architectures.hpp"
50 #include "MachOFileAbstraction.hpp"
51 #include "CacheFileAbstraction.hpp"
53 #include "SupportedArchs.h"
74 const char* dependentsOfPath
;
75 const void* mappedCache
;
76 const char* extractionDir
;
79 bool printDylibVersions
;
88 struct TextInfoSorter
{
89 bool operator()(const TextInfo
& left
, const TextInfo
& right
) {
90 return (left
.textSize
> right
.textSize
);
95 std::map
<uint32_t, const char*> pageToContent
;
96 uint64_t linkeditBase
;
97 bool dependentTargetFound
;
98 std::vector
<TextInfo
> textSegments
;
102 // mmap() an shared cache file read/only but laid out like it would be at runtime
103 static const DyldSharedCache
* mapCacheFile(const char* path
, size_t& cacheLength
)
106 if ( ::stat(path
, &statbuf
) ) {
107 fprintf(stderr
, "Error: stat failed for dyld shared cache at %s\n", path
);
111 int cache_fd
= ::open(path
, O_RDONLY
);
113 fprintf(stderr
, "Error: failed to open shared cache file at %s\n", path
);
117 uint8_t firstPage
[4096];
118 if ( ::pread(cache_fd
, firstPage
, 4096, 0) != 4096 ) {
119 fprintf(stderr
, "Error: failed to read shared cache file at %s\n", path
);
122 const dyld_cache_header
* header
= (dyld_cache_header
*)firstPage
;
123 const dyld_cache_mapping_info
* mappings
= (dyld_cache_mapping_info
*)(firstPage
+ header
->mappingOffset
);
125 size_t vmSize
= (size_t)(mappings
[2].address
+ mappings
[2].size
- mappings
[0].address
);
127 kern_return_t r
= ::vm_allocate(mach_task_self(), &result
, vmSize
, VM_FLAGS_ANYWHERE
);
128 if ( r
!= KERN_SUCCESS
) {
129 fprintf(stderr
, "Error: failed to allocate space to load shared cache file at %s\n", path
);
132 for (int i
=0; i
< 3; ++i
) {
133 void* mapped_cache
= ::mmap((void*)(result
+ mappings
[i
].address
- mappings
[0].address
), (size_t)mappings
[i
].size
,
134 PROT_READ
, MAP_FIXED
| MAP_PRIVATE
, cache_fd
, mappings
[i
].fileOffset
);
135 if (mapped_cache
== MAP_FAILED
) {
136 fprintf(stderr
, "Error: mmap() for shared cache at %s failed, errno=%d\n", path
, errno
);
142 cacheLength
= statbuf
.st_size
;
144 return (DyldSharedCache
*)result
;
150 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");
154 static bool isHaswell()
156 // check system is capable of running x86_64h code
157 struct host_basic_info info
;
158 mach_msg_type_number_t count
= HOST_BASIC_INFO_COUNT
;
159 mach_port_t hostPort
= mach_host_self();
160 kern_return_t result
= host_info(hostPort
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
);
161 mach_port_deallocate(mach_task_self(), hostPort
);
162 if ( result
!= KERN_SUCCESS
)
164 return ( info
.cpu_subtype
== CPU_SUBTYPE_X86_64_H
);
169 * Get the path to the native shared cache for this host
171 static const char* default_shared_cache_path() {
173 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"i386";
176 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"x86_64h";
178 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"x86_64";
179 #elif __ARM_ARCH_5TEJ__
180 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"armv5";
181 #elif __ARM_ARCH_6K__
182 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"armv6";
183 #elif __ARM_ARCH_7K__
184 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"armv7k";
185 #elif __ARM_ARCH_7A__
186 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"armv7";
187 #elif __ARM_ARCH_7F__
188 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"armv7f";
189 #elif __ARM_ARCH_7S__
190 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"armv7s";
191 #elif __ARM64_ARCH_8_32__
192 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"arm64_32";
194 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"arm64e";
196 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME
"arm64";
198 #error unsupported architecture
202 typedef void (*segment_callback_t
)(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
,
203 const Options
& options
, Results
& results
);
208 * List dependencies from the mach-o header at headerAddr
209 * in the same format as 'otool -L'
211 template <typename A
>
212 void print_dependencies(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
,
213 const Options
& options
, Results
& results
) {
214 typedef typename
A::P P
;
215 typedef typename
A::P::E E
;
217 if ( strcmp(options
.dependentsOfPath
, dylibInfo
->path
) != 0 )
219 if ( strcmp(segInfo
->name
, "__TEXT") != 0 )
222 const macho_dylib_command
<P
>* dylib_cmd
;
223 const macho_header
<P
>* mh
= (const macho_header
<P
>*)dylibInfo
->machHeader
;
224 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uintptr_t)dylibInfo
->machHeader
+ sizeof(macho_header
<P
>));
225 const uint32_t cmd_count
= mh
->ncmds();
226 const macho_load_command
<P
>* cmd
= cmds
;
227 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
228 switch ( cmd
->cmd() ) {
231 case LC_REEXPORT_DYLIB
:
232 case LC_LOAD_WEAK_DYLIB
:
233 case LC_LOAD_UPWARD_DYLIB
:
234 dylib_cmd
= (macho_dylib_command
<P
>*)cmd
;
235 if ( options
.printDylibVersions
) {
236 uint32_t compat_vers
= dylib_cmd
->compatibility_version();
237 uint32_t current_vers
= dylib_cmd
->current_version();
238 printf("\t%s", dylib_cmd
->name());
239 if ( compat_vers
!= 0xFFFFFFFF ) {
240 printf("(compatibility version %u.%u.%u, current version %u.%u.%u)\n",
242 (compat_vers
>> 8) & 0xff,
243 (compat_vers
) & 0xff,
244 (current_vers
>> 16),
245 (current_vers
>> 8) & 0xff,
246 (current_vers
) & 0xff);
253 printf("\t%s\n", dylib_cmd
->name());
257 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
259 results
.dependentTargetFound
= true;
263 * Print out a dylib from the shared cache, optionally including the UUID or unslid load address
265 template <typename A
>
266 void print_list(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
,
267 const Options
& options
, Results
& results
)
269 if ( strcmp(segInfo
->name
, "__TEXT") != 0 )
272 if ( options
.printVMAddrs
)
273 printf("0x%08llX ", segInfo
->address
);
274 if ( options
.printInodes
)
275 printf("0x%08llX 0x%08llX ", dylibInfo
->inode
, dylibInfo
->modTime
);
276 if ( options
.printUUIDs
) {
277 if ( dylibInfo
->uuid
!= NULL
) {
278 const uint8_t* uuid
= (uint8_t*)dylibInfo
->uuid
;;
279 printf("<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X> ",
280 uuid
[0], uuid
[1], uuid
[2], uuid
[3],
281 uuid
[4], uuid
[5], uuid
[6], uuid
[7],
282 uuid
[8], uuid
[9], uuid
[10], uuid
[11],
283 uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
286 printf("< no uuid in dylib > ");
288 if ( dylibInfo
->isAlias
)
289 printf("[alias] %s\n", dylibInfo
->path
);
291 printf("%s\n", dylibInfo
->path
);
295 template <typename A
>
296 void collect_size(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
,
297 const Options
& options
, Results
& results
)
299 if ( strcmp(segInfo
->name
, "__TEXT") != 0 )
301 if ( dylibInfo
->isAlias
)
305 info
.textSize
= segInfo
->fileSize
;
306 info
.path
= dylibInfo
->path
;
307 results
.textSegments
.push_back(info
);
313 static void add_linkedit(uint32_t pageStart
, uint32_t pageEnd
, const char* message
, Results
& results
)
315 for (uint32_t p
= pageStart
; p
<= pageEnd
; p
+= 4096) {
316 std::map
<uint32_t, const char*>::iterator pos
= results
.pageToContent
.find(p
);
317 if ( pos
== results
.pageToContent
.end() ) {
318 results
.pageToContent
[p
] = strdup(message
);
321 const char* oldMessage
= pos
->second
;
323 asprintf(&newMesssage
, "%s, %s", oldMessage
, message
);
324 results
.pageToContent
[p
] = newMesssage
;
325 ::free((void*)oldMessage
);
332 * get LINKEDIT info for dylib
334 template <typename A
>
335 void process_linkedit(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
,
336 const Options
& options
, Results
& results
) {
337 typedef typename
A::P P
;
338 typedef typename
A::P::E E
;
339 // filter out symlinks
340 if ( dylibInfo
->isAlias
)
342 const macho_header
<P
>* mh
= (const macho_header
<P
>*)dylibInfo
->machHeader
;
343 uint32_t ncmds
= mh
->ncmds();
344 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((long)mh
+ sizeof(macho_header
<P
>));
345 const macho_load_command
<P
>* cmd
= cmds
;
346 for (uint32_t i
= 0; i
< ncmds
; i
++) {
347 if ( cmd
->cmd() == LC_DYLD_INFO_ONLY
) {
348 macho_dyld_info_command
<P
>* dyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
350 const char* shortName
= strrchr(dylibInfo
->path
, '/') + 1;
351 // add export trie info
352 if ( dyldInfo
->export_size() != 0 ) {
353 //printf("export_off=0x%X\n", dyldInfo->export_off());
354 uint32_t exportPageOffsetStart
= dyldInfo
->export_off() & (-4096);
355 uint32_t exportPageOffsetEnd
= (dyldInfo
->export_off() + dyldInfo
->export_size()) & (-4096);
356 sprintf(message
, "exports from %s", shortName
);
357 add_linkedit(exportPageOffsetStart
, exportPageOffsetEnd
, message
, results
);
360 if ( dyldInfo
->bind_size() != 0 ) {
361 uint32_t bindPageOffsetStart
= dyldInfo
->bind_off() & (-4096);
362 uint32_t bindPageOffsetEnd
= (dyldInfo
->bind_off() + dyldInfo
->bind_size()) & (-4096);
363 sprintf(message
, "bindings from %s", shortName
);
364 add_linkedit(bindPageOffsetStart
, bindPageOffsetEnd
, message
, results
);
366 // add lazy binding info
367 if ( dyldInfo
->lazy_bind_size() != 0 ) {
368 uint32_t lazybindPageOffsetStart
= dyldInfo
->lazy_bind_off() & (-4096);
369 uint32_t lazybindPageOffsetEnd
= (dyldInfo
->lazy_bind_off() + dyldInfo
->lazy_bind_size()) & (-4096);
370 sprintf(message
, "lazy bindings from %s", shortName
);
371 add_linkedit(lazybindPageOffsetStart
, lazybindPageOffsetEnd
, message
, results
);
373 // add weak binding info
374 if ( dyldInfo
->weak_bind_size() != 0 ) {
375 uint32_t weakbindPageOffsetStart
= dyldInfo
->weak_bind_off() & (-4096);
376 uint32_t weakbindPageOffsetEnd
= (dyldInfo
->weak_bind_off() + dyldInfo
->weak_bind_size()) & (-4096);
377 sprintf(message
, "weak bindings from %s", shortName
);
378 add_linkedit(weakbindPageOffsetStart
, weakbindPageOffsetEnd
, message
, results
);
381 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
387 * Print out a .map file similar to what update_dyld_shared_cache created when the cache file was built
389 template <typename A
>
390 void print_map(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
, const Options
& options
, Results
& results
) {
391 if ( !dylibInfo
->isAlias
)
392 printf("0x%08llX - 0x%08llX %s %s\n", segInfo
->address
, segInfo
->address
+ segInfo
->fileSize
, segInfo
->name
, dylibInfo
->path
);
396 static void checkMode(Mode mode
) {
397 if ( mode
!= modeNone
) {
398 fprintf(stderr
, "Error: select one of: -list, -dependents, -info, -slide_info, -verbose_slide_info, -linkedit, -map, -extract, or -size\n");
404 int main (int argc
, const char* argv
[]) {
406 const char* sharedCachePath
= default_shared_cache_path();
409 options
.mode
= modeNone
;
410 options
.printUUIDs
= false;
411 options
.printVMAddrs
= false;
412 options
.printDylibVersions
= false;
413 options
.printInodes
= false;
414 options
.dependentsOfPath
= NULL
;
415 options
.extractionDir
= NULL
;
417 bool printStrings
= false;
418 bool printExports
= false;
420 for (uint32_t i
= 1; i
< argc
; i
++) {
421 const char* opt
= argv
[i
];
423 if (strcmp(opt
, "-list") == 0) {
424 checkMode(options
.mode
);
425 options
.mode
= modeList
;
427 else if (strcmp(opt
, "-dependents") == 0) {
428 checkMode(options
.mode
);
429 options
.mode
= modeDependencies
;
430 options
.dependentsOfPath
= argv
[++i
];
432 fprintf(stderr
, "Error: option -depdendents requires an argument\n");
437 else if (strcmp(opt
, "-linkedit") == 0) {
438 checkMode(options
.mode
);
439 options
.mode
= modeLinkEdit
;
441 else if (strcmp(opt
, "-info") == 0) {
442 checkMode(options
.mode
);
443 options
.mode
= modeInfo
;
445 else if (strcmp(opt
, "-slide_info") == 0) {
446 checkMode(options
.mode
);
447 options
.mode
= modeSlideInfo
;
449 else if (strcmp(opt
, "-verbose_slide_info") == 0) {
450 checkMode(options
.mode
);
451 options
.mode
= modeVerboseSlideInfo
;
453 else if (strcmp(opt
, "-accelerator_info") == 0) {
454 checkMode(options
.mode
);
455 options
.mode
= modeAcceleratorInfo
;
457 else if (strcmp(opt
, "-text_info") == 0) {
458 checkMode(options
.mode
);
459 options
.mode
= modeTextInfo
;
461 else if (strcmp(opt
, "-local_symbols") == 0) {
462 checkMode(options
.mode
);
463 options
.mode
= modeLocalSymbols
;
465 else if (strcmp(opt
, "-strings") == 0) {
466 if (options
.mode
!= modeStrings
)
467 checkMode(options
.mode
);
468 options
.mode
= modeStrings
;
471 else if (strcmp(opt
, "-exports") == 0) {
472 if (options
.mode
!= modeStrings
)
473 checkMode(options
.mode
);
474 options
.mode
= modeStrings
;
477 else if (strcmp(opt
, "-map") == 0) {
478 checkMode(options
.mode
);
479 options
.mode
= modeMap
;
481 else if (strcmp(opt
, "-size") == 0) {
482 checkMode(options
.mode
);
483 options
.mode
= modeSize
;
485 else if (strcmp(opt
, "-extract") == 0) {
486 checkMode(options
.mode
);
487 options
.mode
= modeExtract
;
488 options
.extractionDir
= argv
[++i
];
490 fprintf(stderr
, "Error: option -extract requires a directory argument\n");
495 else if (strcmp(opt
, "-uuid") == 0) {
496 options
.printUUIDs
= true;
498 else if (strcmp(opt
, "-inode") == 0) {
499 options
.printInodes
= true;
501 else if (strcmp(opt
, "-versions") == 0) {
502 options
.printDylibVersions
= true;
504 else if (strcmp(opt
, "-vmaddr") == 0) {
505 options
.printVMAddrs
= true;
508 fprintf(stderr
, "Error: unrecognized option %s\n", opt
);
514 sharedCachePath
= opt
;
518 if ( options
.mode
== modeNone
) {
519 fprintf(stderr
, "Error: select one of -list, -dependents, -info, -linkedit, or -map\n");
524 if ( options
.mode
!= modeSlideInfo
&& options
.mode
!= modeVerboseSlideInfo
) {
525 if ( options
.printUUIDs
&& (options
.mode
!= modeList
) )
526 fprintf(stderr
, "Warning: -uuid option ignored outside of -list mode\n");
528 if ( options
.printVMAddrs
&& (options
.mode
!= modeList
) )
529 fprintf(stderr
, "Warning: -vmaddr option ignored outside of -list mode\n");
531 if ( options
.printDylibVersions
&& (options
.mode
!= modeDependencies
) )
532 fprintf(stderr
, "Warning: -versions option ignored outside of -dependents mode\n");
534 if ( (options
.mode
== modeDependencies
) && (options
.dependentsOfPath
== NULL
) ) {
535 fprintf(stderr
, "Error: -dependents given, but no dylib path specified\n");
541 const DyldSharedCache
* dyldCache
= nullptr;
542 bool dyldCacheIsLive
= true;
543 size_t cacheLength
= 0;
544 if ( sharedCachePath
!= nullptr ) {
545 dyldCache
= mapCacheFile(sharedCachePath
, cacheLength
);
546 dyldCacheIsLive
= false;
549 #if __MAC_OS_X_VERSION_MIN_REQUIRED && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101300)
550 fprintf(stderr
, "this tool needs to run on macOS 10.13 or later\n");
553 dyldCache
= (DyldSharedCache
*)_dyld_get_shared_cache_range(&cacheLength
);
557 options
.mappedCache
= dyldCache
;
559 if ( options
.mode
== modeSlideInfo
|| options
.mode
== modeVerboseSlideInfo
) {
560 const dyldCacheHeader
<LittleEndian
>* header
= (dyldCacheHeader
<LittleEndian
>*)options
.mappedCache
;
561 if ( header
->slideInfoOffset() == 0 ) {
562 fprintf(stderr
, "Error: dyld shared cache does not contain slide info\n");
565 const dyldCacheFileMapping
<LittleEndian
>* mappings
= (dyldCacheFileMapping
<LittleEndian
>*)((char*)options
.mappedCache
+ header
->mappingOffset());
566 const dyldCacheFileMapping
<LittleEndian
>* textMapping
= &mappings
[0];
567 const dyldCacheFileMapping
<LittleEndian
>* dataMapping
= &mappings
[1];
568 const dyldCacheFileMapping
<LittleEndian
>* linkEditMapping
= &mappings
[2];
569 uint64_t dataStartAddress
= dataMapping
->address();
570 uint64_t dataSize
= dataMapping
->size();
571 uint64_t slideInfoMappedOffset
= (header
->slideInfoOffset()-linkEditMapping
->file_offset()) + (linkEditMapping
->address() - textMapping
->address());
572 const dyldCacheSlideInfo
<LittleEndian
>* slideInfoHeader
= (dyldCacheSlideInfo
<LittleEndian
>*)((char*)options
.mappedCache
+slideInfoMappedOffset
);
573 printf("slide info version=%d\n", slideInfoHeader
->version());
574 if ( slideInfoHeader
->version() == 1 ) {
575 printf("toc_count=%d, data page count=%lld\n", slideInfoHeader
->toc_count(), dataSize
/4096);
576 const dyldCacheSlideInfoEntry
* entries
= (dyldCacheSlideInfoEntry
*)((char*)slideInfoHeader
+ slideInfoHeader
->entries_offset());
577 for(int i
=0; i
< slideInfoHeader
->toc_count(); ++i
) {
578 printf("0x%08llX: [% 5d,% 5d] ", dataStartAddress
+ i
*4096, i
, slideInfoHeader
->toc(i
));
579 const dyldCacheSlideInfoEntry
* entry
= &entries
[slideInfoHeader
->toc(i
)];
580 for(int j
=0; j
< slideInfoHeader
->entries_size(); ++j
)
581 printf("%02X", entry
->bits
[j
]);
585 else if ( slideInfoHeader
->version() == 2 ) {
586 const dyldCacheSlideInfo2
<LittleEndian
>* slideInfo
= (dyldCacheSlideInfo2
<LittleEndian
>*)(slideInfoHeader
);
587 printf("page_size=%d\n", slideInfo
->page_size());
588 printf("delta_mask=0x%016llX\n", slideInfo
->delta_mask());
589 printf("value_add=0x%016llX\n", slideInfo
->value_add());
590 printf("page_starts_count=%d, page_extras_count=%d\n", slideInfo
->page_starts_count(), slideInfo
->page_extras_count());
591 const uint16_t* starts
= (uint16_t* )((char*)slideInfo
+ slideInfo
->page_starts_offset());
592 const uint16_t* extras
= (uint16_t* )((char*)slideInfo
+ slideInfo
->page_extras_offset());
593 for (int i
=0; i
< slideInfo
->page_starts_count(); ++i
) {
594 const uint16_t start
= starts
[i
];
595 auto rebaseChain
= [&](uint8_t* pageContent
, uint16_t startOffset
)
597 uintptr_t slideAmount
= 0;
598 const uintptr_t deltaMask
= (uintptr_t)(slideInfo
->delta_mask());
599 const uintptr_t valueMask
= ~deltaMask
;
600 const uintptr_t valueAdd
= (uintptr_t)(slideInfo
->value_add());
601 const unsigned deltaShift
= __builtin_ctzll(deltaMask
) - 2;
603 uint32_t pageOffset
= startOffset
;
605 while ( delta
!= 0 ) {
606 uint8_t* loc
= pageContent
+ pageOffset
;
607 uintptr_t rawValue
= *((uintptr_t*)loc
);
608 delta
= (uint32_t)((rawValue
& deltaMask
) >> deltaShift
);
609 uintptr_t value
= (rawValue
& valueMask
);
612 value
+= slideAmount
;
614 printf(" [% 5d + 0x%04llX]: 0x%016llX\n", i
, (uint64_t)(pageOffset
), (uint64_t)rawValue
);
618 const uint8_t* dataPagesStart
= (uint8_t*)((char*)options
.mappedCache
+ dataMapping
->file_offset());
619 if ( start
== DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE
) {
620 printf("page[% 5d]: no rebasing\n", i
);
622 else if ( start
& DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA
) {
623 printf("page[% 5d]: ", i
);
624 int j
=(start
& 0x3FFF);
627 uint16_t aStart
= extras
[j
];
628 printf("start=0x%04X ", aStart
& 0x3FFF);
629 if ( options
.mode
== modeVerboseSlideInfo
) {
630 uint8_t* page
= (uint8_t*)(long)(dataPagesStart
+ (slideInfo
->page_size()*i
));
631 uint16_t pageStartOffset
= (aStart
& 0x3FFF)*4;
632 rebaseChain(page
, pageStartOffset
);
634 done
= (extras
[j
] & DYLD_CACHE_SLIDE_PAGE_ATTR_END
);
640 printf("page[% 5d]: start=0x%04X\n", i
, starts
[i
]);
641 if ( options
.mode
== modeVerboseSlideInfo
) {
642 uint8_t* page
= (uint8_t*)(long)(dataPagesStart
+ (slideInfo
->page_size()*i
));
643 uint16_t pageStartOffset
= start
*4;
644 rebaseChain(page
, pageStartOffset
);
649 else if ( slideInfoHeader
->version() == 3 ) {
650 const dyldCacheSlideInfo3
<LittleEndian
>* slideInfo
= (dyldCacheSlideInfo3
<LittleEndian
>*)(slideInfoHeader
);
651 printf("page_size=%d\n", slideInfo
->page_size());
652 printf("page_starts_count=%d\n", slideInfo
->page_starts_count());
653 printf("auth_value_add=0x%016llX\n", slideInfo
->auth_value_add());
654 const uint8_t* dataSegmentStart
= (uint8_t*)((char*)options
.mappedCache
+ dataMapping
->file_offset());
655 for (int i
=0; i
< slideInfo
->page_starts_count(); ++i
) {
656 const uint16_t start
= slideInfo
->page_starts(i
);
657 if ( start
== 0xFFFF ) {
658 printf("page[% 5d]: no rebasing\n", i
);
661 printf("page[% 5d]: start=0x%04X\n", i
, start
);
662 if ( options
.mode
== modeVerboseSlideInfo
) {
663 typedef Pointer64
<LittleEndian
> P
;
664 typedef typename
P::uint_t pint_t
;
665 const uint8_t* pageStart
= dataSegmentStart
+ (i
* slideInfo
->page_size());
666 pint_t delta
= start
;
667 const uint8_t* rebaseLocation
= pageStart
;
669 rebaseLocation
+= delta
;
670 pint_t value
= (pint_t
)P::getP(*(uint64_t*)rebaseLocation
);
671 delta
= ( (value
& 0x3FF8000000000000) >> 51) * sizeof(pint_t
);
673 // Regular pointer which needs to fit in 51-bits of value.
674 // C++ RTTI uses the top bit, so we'll allow the whole top-byte
675 // and the signed-extended bottom 43-bits to be fit in to 51-bits.
676 uint64_t top8Bits
= value
& 0x007F80000000000ULL
;
677 uint64_t bottom43Bits
= value
& 0x000007FFFFFFFFFFULL
;
678 uint64_t targetValue
= ( top8Bits
<< 13 ) | (((intptr_t)(bottom43Bits
<< 21) >> 21) & 0x00FFFFFFFFFFFFFF);
679 printf(" [% 5d + 0x%04llX]: 0x%016llX\n", i
, (uint64_t)(rebaseLocation
- pageStart
), targetValue
);
680 } while (delta
!= 0);
685 else if ( slideInfoHeader
->version() == 4 ) {
686 const dyld_cache_slide_info4
* slideInfo
= (dyld_cache_slide_info4
*)(slideInfoHeader
);
687 printf("page_size=%d\n", slideInfo
->page_size
);
688 printf("delta_mask=0x%016llX\n", slideInfo
->delta_mask
);
689 printf("value_add=0x%016llX\n", slideInfo
->value_add
);
690 printf("page_starts_count=%d, page_extras_count=%d\n", slideInfo
->page_starts_count
, slideInfo
->page_extras_count
);
691 const uint16_t* starts
= (uint16_t* )((char*)slideInfo
+ slideInfo
->page_starts_offset
);
692 const uint16_t* extras
= (uint16_t* )((char*)slideInfo
+ slideInfo
->page_extras_offset
);
693 for (int i
=0; i
< slideInfo
->page_starts_count
; ++i
) {
694 const uint16_t start
= starts
[i
];
695 auto rebaseChainV4
= [&](uint8_t* pageContent
, uint16_t startOffset
)
697 uintptr_t slideAmount
= 0;
698 const uintptr_t deltaMask
= (uintptr_t)(slideInfo
->delta_mask
);
699 const uintptr_t valueMask
= ~deltaMask
;
700 const uintptr_t valueAdd
= (uintptr_t)(slideInfo
->value_add
);
701 const unsigned deltaShift
= __builtin_ctzll(deltaMask
) - 2;
703 uint32_t pageOffset
= startOffset
;
705 while ( delta
!= 0 ) {
706 uint8_t* loc
= pageContent
+ pageOffset
;
707 uint32_t rawValue
= *((uint32_t*)loc
);
708 delta
= (uint32_t)((rawValue
& deltaMask
) >> deltaShift
);
709 uintptr_t value
= (rawValue
& valueMask
);
710 if ( (value
& 0xFFFF8000) == 0 ) {
711 // small positive non-pointer, use as-is
713 else if ( (value
& 0x3FFF8000) == 0x3FFF8000 ) {
714 // small negative non-pointer
719 value
+= slideAmount
;
721 printf(" [% 5d + 0x%04X]: 0x%08X\n", i
, pageOffset
, rawValue
);
725 const uint8_t* dataPagesStart
= (uint8_t*)((char*)options
.mappedCache
+ dataMapping
->file_offset());
726 if ( start
== DYLD_CACHE_SLIDE4_PAGE_NO_REBASE
) {
727 printf("page[% 5d]: no rebasing\n", i
);
729 else if ( start
& DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA
) {
730 printf("page[% 5d]: ", i
);
731 int j
=(start
& DYLD_CACHE_SLIDE4_PAGE_INDEX
);
734 uint16_t aStart
= extras
[j
];
735 printf("start=0x%04X ", aStart
& DYLD_CACHE_SLIDE4_PAGE_INDEX
);
736 if ( options
.mode
== modeVerboseSlideInfo
) {
737 uint8_t* page
= (uint8_t*)(long)(dataPagesStart
+ (slideInfo
->page_size
*i
));
738 uint16_t pageStartOffset
= (aStart
& DYLD_CACHE_SLIDE4_PAGE_INDEX
)*4;
739 rebaseChainV4(page
, pageStartOffset
);
741 done
= (extras
[j
] & DYLD_CACHE_SLIDE4_PAGE_EXTRA_END
);
747 printf("page[% 5d]: start=0x%04X\n", i
, starts
[i
]);
748 if ( options
.mode
== modeVerboseSlideInfo
) {
749 uint8_t* page
= (uint8_t*)(long)(dataPagesStart
+ (slideInfo
->page_size
*i
));
750 uint16_t pageStartOffset
= start
*4;
751 rebaseChainV4(page
, pageStartOffset
);
759 if ( options
.mode
== modeInfo
) {
760 const dyldCacheHeader
<LittleEndian
>* header
= (dyldCacheHeader
<LittleEndian
>*)options
.mappedCache
;
762 if ( header
->mappingOffset() >= 0x68 ) {
763 const uint8_t* uuid
= header
->uuid();
764 printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
765 uuid
[0], uuid
[1], uuid
[2], uuid
[3],
766 uuid
[4], uuid
[5], uuid
[6], uuid
[7],
767 uuid
[8], uuid
[9], uuid
[10], uuid
[11],
768 uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
773 if ( header
->mappingOffset() >= 0xE0 ) {
774 // HACK until this uses new header
775 uint32_t platform
= *((uint32_t*)(((char*)header
) + 0xD8));
776 uint32_t bitfield
= *((uint32_t*)(((char*)header
) + 0xDC));
777 uint32_t simulator
= bitfield
& 0x200;
778 uint32_t locallyBuiltCache
= bitfield
& 0x400;
781 printf("platform: macOS\n");
785 printf("platform: iOS simulator\n");
787 printf("platform: iOS\n");
791 printf("platform: tvOS simulator\n");
793 printf("platform: tvOS\n");
797 printf("platform: watchOS simulator\n");
799 printf("platform: watchOS\n");
802 printf("platform: bridgeOS\n");
805 printf("platform: 0x%08X 0x%08X\n", platform
, simulator
);
807 printf("built by: %s\n", locallyBuiltCache
? "local machine" : "B&I");
809 printf("image count: %u\n", header
->imagesCount());
810 if ( (header
->mappingOffset() >= 0x78) && (header
->branchPoolsOffset() != 0) ) {
811 printf("branch pool count: %u\n", header
->branchPoolsCount());
813 printf("mappings:\n");
814 const dyldCacheFileMapping
<LittleEndian
>* mappings
= (dyldCacheFileMapping
<LittleEndian
>*)((char*)options
.mappedCache
+ header
->mappingOffset());
815 for (uint32_t i
=0; i
< header
->mappingCount(); ++i
) {
816 if ( mappings
[i
].init_prot() & VM_PROT_EXECUTE
)
817 printf(" __TEXT %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
818 mappings
[i
].size()/(1024*1024), mappings
[i
].file_offset(), mappings
[i
].file_offset() + mappings
[i
].size(),
819 mappings
[i
].address(), mappings
[i
].address() + mappings
[i
].size());
820 else if ( mappings
[i
]. init_prot() & VM_PROT_WRITE
)
821 printf(" __DATA %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
822 mappings
[i
].size()/(1024*1024), mappings
[i
].file_offset(), mappings
[i
].file_offset() + mappings
[i
].size(),
823 mappings
[i
].address(), mappings
[i
].address() + mappings
[i
].size());
824 else if ( mappings
[i
].init_prot() & VM_PROT_READ
)
825 printf(" __LINKEDIT %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
826 mappings
[i
].size()/(1024*1024), mappings
[i
].file_offset(), mappings
[i
].file_offset() + mappings
[i
].size(),
827 mappings
[i
].address(), mappings
[i
].address() + mappings
[i
].size());
829 if ( header
->codeSignatureOffset() != 0 ) {
830 uint64_t size
= cacheLength
- header
->codeSignatureOffset();
831 uint64_t csAddr
= mappings
[header
->mappingCount()-1].address() + mappings
[header
->mappingCount()-1].size();
833 printf(" code sign %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
834 size
/(1024*1024), header
->codeSignatureOffset(), header
->codeSignatureOffset() + size
, csAddr
, csAddr
+ size
);
836 printf("slide info: %4lluKB, file offset: 0x%08llX -> 0x%08llX\n",
837 header
->slideInfoSize()/1024, header
->slideInfoOffset(), header
->slideInfoOffset() + header
->slideInfoSize());
838 if ( header
->localSymbolsOffset() != 0 )
839 printf("local symbols: %3lluMB, file offset: 0x%08llX -> 0x%08llX\n",
840 header
->localSymbolsSize()/(1024*1024), header
->localSymbolsOffset(), header
->localSymbolsOffset() + header
->localSymbolsSize());
841 if ( (header
->mappingOffset() >= 0x78) && (header
->accelerateInfoSize() != 0) )
842 printf("accelerate tab: %3lluKB, address: 0x%08llX -> 0x%08llX\n",
843 header
->accelerateInfoSize()/1024, header
->accelerateInfoAddr(), header
->accelerateInfoAddr() + header
->accelerateInfoSize());
845 else if ( options
.mode
== modeAcceleratorInfo
) {
846 const dyldCacheHeader
<LittleEndian
>* header
= (dyldCacheHeader
<LittleEndian
>*)options
.mappedCache
;
847 if ( (header
->mappingOffset() < sizeof(dyldCacheHeader
<LittleEndian
>)) || (header
->accelerateInfoSize() == 0) ) {
848 printf("no accelerator info\n");
851 const dyldCacheFileMapping
<LittleEndian
>* mappings
= (dyldCacheFileMapping
<LittleEndian
>*)((char*)options
.mappedCache
+ header
->mappingOffset());
852 uint64_t aiAddr
= header
->accelerateInfoAddr();
853 dyldCacheAcceleratorInfo
<LittleEndian
>* accelInfo
= NULL
;
854 for (uint32_t i
=0; i
< header
->mappingCount(); ++i
) {
855 if ( (mappings
[i
].address() <= aiAddr
) && (aiAddr
< mappings
[i
].address()+mappings
[i
].size()) ) {
856 uint64_t offset
= aiAddr
- mappings
[i
].address() + mappings
[i
].file_offset();
857 accelInfo
= (dyldCacheAcceleratorInfo
<LittleEndian
>*)((uint8_t*)options
.mappedCache
+ offset
);
860 if ( accelInfo
== NULL
) {
861 printf("accelerator info not in any mapped range\n");
864 const dyldCacheImageInfo
<LittleEndian
>* images
= (dyldCacheImageInfo
<LittleEndian
>*)((char*)options
.mappedCache
+ header
->imagesOffset());
865 const dyldCacheImageInfoExtra
<LittleEndian
>* imagesExtra
= (dyldCacheImageInfoExtra
<LittleEndian
>*)((char*)accelInfo
+ accelInfo
->imagesExtrasOffset());
866 const uint16_t* dependencyArray
= (uint16_t*)((char*)accelInfo
+ accelInfo
->depListOffset());
867 const uint16_t* reExportArray
= (uint16_t*)((char*)accelInfo
+ accelInfo
->reExportListOffset());
868 printf("extra image info (count=%u):\n", accelInfo
->imageExtrasCount());
869 for (uint32_t i
=0; i
< accelInfo
->imageExtrasCount(); ++i
) {
870 printf(" image[%3u] %s:\n", i
, (char*)options
.mappedCache
+images
[i
].pathFileOffset());
871 printf(" exports trie: addr=0x%llX, size=0x%08X\n", imagesExtra
[i
].exportsTrieAddr(), imagesExtra
[i
].exportsTrieSize());
872 if ( imagesExtra
[i
].weakBindingsSize() )
873 printf(" weak bind info: addr=0x%llX, size=0x%08X\n", imagesExtra
[i
].weakBindingsAddr(), imagesExtra
[i
].weakBindingsSize());
874 printf(" dependents: ");
875 for (uint32_t d
=imagesExtra
[i
].dependentsStartArrayIndex(); dependencyArray
[d
] != 0xFFFF; ++d
) {
876 uint16_t depIndex
= dependencyArray
[d
];
877 if ( depIndex
& 0x8000 )
878 printf(" up(%d) ", depIndex
& 0x7FFF);
880 printf(" %d ", depIndex
);
883 printf(" re-exports: ");
884 for (uint32_t r
=imagesExtra
[i
].reExportsStartArrayIndex(); reExportArray
[r
] != 0xFFFF; ++r
)
885 printf(" %d ", reExportArray
[r
]);
888 printf("libdyld.dylib:\n");
889 printf(" __dyld section address: 0x%llX\n", accelInfo
->dyldSectionAddr());
890 printf("initializers (count=%u):\n", accelInfo
->initializersCount());
891 const dyldCacheAcceleratorInitializer
<LittleEndian
>* initializers
= (dyldCacheAcceleratorInitializer
<LittleEndian
>*)((char*)accelInfo
+ accelInfo
->initializersOffset());
892 for (uint32_t i
=0; i
< accelInfo
->initializersCount(); ++i
) {
893 printf(" image[%3u] 0x%llX\n", initializers
[i
].imageIndex(), mappings
[0].address() + initializers
[i
].functionOffset());
895 printf("DOF sections (count=%u):\n", accelInfo
->dofSectionsCount());
896 const dyldCacheAcceleratorDOFEntry
<LittleEndian
>* dofs
= (dyldCacheAcceleratorDOFEntry
<LittleEndian
>*)((char*)accelInfo
+ accelInfo
->dofSectionsOffset());
897 for (uint32_t i
=0; i
< accelInfo
->dofSectionsCount(); ++i
) {
898 printf(" image[%3u] 0x%llX -> 0x%llX\n", dofs
[i
].imageIndex(), dofs
[i
].sectionAddress(), dofs
[i
].sectionAddress()+dofs
[i
].sectionSize());
900 printf("bottom up order (count=%u):\n", accelInfo
->imageExtrasCount());
901 const uint16_t* bottomUpArray
= (uint16_t*)((char*)accelInfo
+ accelInfo
->bottomUpListOffset());
902 for (uint32_t i
=0; i
< accelInfo
->imageExtrasCount(); ++i
) {
903 unsigned imageIndex
= bottomUpArray
[i
];
904 if ( imageIndex
< accelInfo
->imageExtrasCount() )
905 printf(" image[%3u] %s\n", imageIndex
, (char*)options
.mappedCache
+ images
[imageIndex
].pathFileOffset());
907 printf(" image[%3u] BAD INDEX\n", imageIndex
);
909 printf("range table (count=%u):\n", accelInfo
->rangeTableCount());
910 const dyldCacheAcceleratorRangeEntry
<LittleEndian
>* rangeTable
= (dyldCacheAcceleratorRangeEntry
<LittleEndian
>*)((char*)accelInfo
+ accelInfo
->rangeTableOffset());
911 for (uint32_t i
=0; i
< accelInfo
->rangeTableCount(); ++i
) {
912 const dyldCacheAcceleratorRangeEntry
<LittleEndian
>& entry
= rangeTable
[i
];
913 printf(" 0x%llX -> 0x%llX %s\n", entry
.startAddress(), entry
.startAddress() + entry
.size(), (char*)options
.mappedCache
+ images
[entry
.imageIndex()].pathFileOffset());
915 printf("dylib trie (size=%u):\n", accelInfo
->dylibTrieSize());
916 const uint8_t* dylibTrieStart
= (uint8_t*)accelInfo
+ accelInfo
->dylibTrieOffset();
917 const uint8_t* dylibTrieEnd
= dylibTrieStart
+ accelInfo
->dylibTrieSize();
918 std::vector
<DylibIndexTrie::Entry
> dylibEntries
;
919 if ( !Trie
<DylibIndex
>::parseTrie(dylibTrieStart
, dylibTrieEnd
, dylibEntries
) )
920 printf(" malformed dylibs trie\n");
921 for (const DylibIndexTrie::Entry
& x
: dylibEntries
) {
922 printf(" image[%3u] %s\n", x
.info
.index
, x
.name
.c_str());
927 else if ( options
.mode
== modeTextInfo
) {
928 const dyldCacheHeader
<LittleEndian
>* header
= (dyldCacheHeader
<LittleEndian
>*)options
.mappedCache
;
929 if ( (header
->mappingOffset() < sizeof(dyldCacheHeader
<LittleEndian
>)) || (header
->imagesTextCount() == 0) ) {
930 printf("no text info\n");
933 const dyldCacheImageTextInfo
<LittleEndian
>* imagesText
= (dyldCacheImageTextInfo
<LittleEndian
>*)((char*)options
.mappedCache
+ header
->imagesTextOffset());
934 const dyldCacheImageTextInfo
<LittleEndian
>* imagesTextEnd
= &imagesText
[header
->imagesTextCount()];
935 printf("dylib text infos (count=%llu):\n", header
->imagesTextCount());
936 for (const dyldCacheImageTextInfo
<LittleEndian
>* p
=imagesText
; p
< imagesTextEnd
; ++p
) {
937 printf(" 0x%09llX -> 0x%09llX <", p
->loadAddress(), p
->loadAddress() + p
->textSegmentSize());
938 for (int i
=0; i
<16; ++i
) {
947 printf("%02X", p
->uuid()[i
]);
949 printf("> %s\n", (char*)options
.mappedCache
+ p
->pathOffset());
953 else if ( options
.mode
== modeLocalSymbols
) {
954 const dyldCacheHeader
<LittleEndian
>* header
= (dyldCacheHeader
<LittleEndian
>*)options
.mappedCache
;
955 if ( header
->localSymbolsOffset() == 0 ) {
956 fprintf(stderr
, "Error: dyld shared cache does not contain local symbols info\n");
959 const bool is64
= (strstr((char*)options
.mappedCache
, "64") != NULL
);
960 const dyldCacheImageInfo
<LittleEndian
>* imageInfos
= (dyldCacheImageInfo
<LittleEndian
>*)((char*)options
.mappedCache
+ header
->imagesOffset());
961 const dyldCacheLocalSymbolsInfo
<LittleEndian
>* localsInfo
= (dyldCacheLocalSymbolsInfo
<LittleEndian
>*)((char*)options
.mappedCache
+ header
->localSymbolsOffset());
962 const uint32_t nlistFileOffset
= (uint32_t)(header
->localSymbolsOffset() + localsInfo
->nlistOffset());
963 const uint32_t nlistCount
= localsInfo
->nlistCount();
964 const uint32_t nlistByteSize
= is64
? nlistCount
*16 : nlistCount
*12;
965 const uint32_t stringsFileOffset
= (uint32_t)(header
->localSymbolsOffset() + localsInfo
->stringsOffset());
966 const uint32_t stringsSize
= localsInfo
->stringsSize();
967 const uint32_t entriesCount
= localsInfo
->entriesCount();
968 const dyldCacheLocalSymbolEntry
<LittleEndian
>* entries
= (dyldCacheLocalSymbolEntry
<LittleEndian
>*)((char*)localsInfo
+ localsInfo
->entriesOffset());
969 printf("local symbols nlist array: %3uMB, file offset: 0x%08X -> 0x%08X\n", nlistByteSize
/(1024*1024), nlistFileOffset
, nlistFileOffset
+nlistByteSize
);
970 printf("local symbols string pool: %3uMB, file offset: 0x%08X -> 0x%08X\n", stringsSize
/(1024*1024), stringsFileOffset
, stringsFileOffset
+stringsSize
);
971 printf("local symbols by dylib (count=%d):\n", entriesCount
);
972 //const char* stringPool = (char*)options.mappedCache + stringsFileOffset;
973 for (int i
=0; i
< entriesCount
; ++i
) {
974 const char* imageName
= (char*)options
.mappedCache
+ imageInfos
[i
].pathFileOffset();
975 printf(" nlistStartIndex=%5d, nlistCount=%5d, image=%s\n", entries
[i
].nlistStartIndex(), entries
[i
].nlistCount(), imageName
);
978 const nlist_64
* symTab
= (nlist_64
*)((char*)options
.mappedCache
+ nlistFileOffset
);
979 for (int e
=0; e
< entries
[i
].nlistCount(); ++e
) {
980 const nlist_64
* entry
= &symTab
[entries
[i
].nlistStartIndex()+e
];
981 printf(" nlist[%d].str=%d, %s\n", e
, entry
->n_un
.n_strx
, &stringPool
[entry
->n_un
.n_strx
]);
982 printf(" nlist[%d].value=0x%0llX\n", e
, entry
->n_value
);
988 else if ( options
.mode
== modeStrings
) {
990 dyldCache
->forEachImage(^(const mach_header
*mh
, const char *installName
) {
991 const dyld3::MachOAnalyzer
* ma
= (dyld3::MachOAnalyzer
*)mh
;
992 int64_t slide
= ma
->getSlide();
993 ma
->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo
& info
, bool malformedSectionRange
, bool& stop
) {
994 if ( ( (info
.sectFlags
& SECTION_TYPE
) == S_CSTRING_LITERALS
) ) {
995 if ( malformedSectionRange
) {
999 const uint8_t* content
= (uint8_t*)(info
.sectAddr
+ slide
);
1000 const char* s
= (char*)content
;
1001 const char* end
= s
+ info
.sectSize
;
1003 printf("%s: %s\n", ma
->installName(), s
);
1014 dyldCache
->forEachImage(^(const mach_header
*mh
, const char *installName
) {
1015 const dyld3::MachOAnalyzer
* ma
= (dyld3::MachOAnalyzer
*)mh
;
1016 uint32_t exportTrieRuntimeOffset
;
1017 uint32_t exportTrieSize
;
1018 if ( ma
->hasExportTrie(exportTrieRuntimeOffset
, exportTrieSize
) ) {
1019 const uint8_t* start
= (uint8_t*)mh
+ exportTrieRuntimeOffset
;
1020 const uint8_t* end
= start
+ exportTrieSize
;
1021 std::vector
<ExportInfoTrie::Entry
> exports
;
1022 if ( !ExportInfoTrie::parseTrie(start
, end
, exports
) ) {
1026 for (const ExportInfoTrie::Entry
& entry
: exports
) {
1027 printf("%s: %s\n", ma
->installName(), entry
.name
.c_str());
1033 else if ( options
.mode
== modeExtract
) {
1034 char pathBuffer
[PATH_MAX
];
1035 uint32_t bufferSize
= PATH_MAX
;
1036 if ( _NSGetExecutablePath(pathBuffer
, &bufferSize
) != 0 ) {
1037 fprintf(stderr
, "Error: could not get path of program\n");
1040 char* last
= strrchr(pathBuffer
, '/');
1041 strcpy(last
+1, "../../lib/dsc_extractor.bundle");
1042 void* handle
= dlopen(pathBuffer
, RTLD_LAZY
);
1043 if ( handle
== NULL
) {
1044 fprintf(stderr
, "Error: dsc_extractor.bundle could not be loaded at %s\n", pathBuffer
);
1048 typedef int (*extractor_proc
)(const char* shared_cache_file_path
, const char* extraction_root_path
,
1049 void (^progress
)(unsigned current
, unsigned total
));
1051 extractor_proc proc
= (extractor_proc
)dlsym(handle
, "dyld_shared_cache_extract_dylibs_progress");
1052 if ( proc
== NULL
) {
1053 fprintf(stderr
, "Error: dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
1057 int result
= (*proc
)(sharedCachePath
, options
.extractionDir
, ^(unsigned c
, unsigned total
) { } );
1061 segment_callback_t callback
= nullptr;
1062 if ( strcmp((char*)options
.mappedCache
, "dyld_v1 i386") == 0 ) {
1063 switch ( options
.mode
) {
1065 callback
= print_list
<x86
>;
1068 callback
= print_map
<x86
>;
1070 case modeDependencies
:
1071 callback
= print_dependencies
<x86
>;
1074 callback
= process_linkedit
<x86
>;
1077 callback
= collect_size
<x86
>;
1082 case modeVerboseSlideInfo
:
1083 case modeAcceleratorInfo
:
1085 case modeLocalSymbols
:
1091 else if ( (strcmp((char*)options
.mappedCache
, "dyld_v1 x86_64") == 0)
1092 || (strcmp((char*)options
.mappedCache
, "dyld_v1 x86_64h") == 0) ) {
1093 switch ( options
.mode
) {
1095 callback
= print_list
<x86_64
>;
1098 callback
= print_map
<x86_64
>;
1100 case modeDependencies
:
1101 callback
= print_dependencies
<x86_64
>;
1104 callback
= process_linkedit
<x86_64
>;
1107 callback
= collect_size
<x86_64
>;
1112 case modeVerboseSlideInfo
:
1113 case modeAcceleratorInfo
:
1115 case modeLocalSymbols
:
1121 else if ( (strncmp((char*)options
.mappedCache
, "dyld_v1 armv", 14) == 0)
1122 || (strncmp((char*)options
.mappedCache
, "dyld_v1 armv", 13) == 0)
1123 #if SUPPORT_ARCH_arm64_32
1124 || (strcmp((char*)options
.mappedCache
, "dyld_v1arm64_32") == 0)
1127 switch ( options
.mode
) {
1129 callback
= print_list
<arm
>;
1132 callback
= print_map
<arm
>;
1134 case modeDependencies
:
1135 callback
= print_dependencies
<arm
>;
1138 callback
= process_linkedit
<arm
>;
1141 callback
= collect_size
<arm
>;
1146 case modeVerboseSlideInfo
:
1147 case modeAcceleratorInfo
:
1149 case modeLocalSymbols
:
1155 else if ( (strcmp((char*)options
.mappedCache
, "dyld_v1 arm64") == 0)
1156 #if SUPPORT_ARCH_arm64e
1157 || (strcmp((char*)options
.mappedCache
, "dyld_v1 arm64e") == 0)
1160 switch ( options
.mode
) {
1162 callback
= print_list
<arm64
>;
1165 callback
= print_map
<arm64
>;
1167 case modeDependencies
:
1168 callback
= print_dependencies
<arm64
>;
1171 callback
= process_linkedit
<arm64
>;
1174 callback
= collect_size
<arm64
>;
1179 case modeVerboseSlideInfo
:
1180 case modeAcceleratorInfo
:
1182 case modeLocalSymbols
:
1188 #if SUPPORT_ARCH_arm64_32
1189 else if ( (strcmp((char*)options
.mappedCache
, "dyld_v1arm64_32") == 0) ) {
1190 switch ( options
.mode
) {
1192 callback
= print_list
<arm64_32
>;
1195 callback
= print_map
<arm64_32
>;
1197 case modeDependencies
:
1198 callback
= print_dependencies
<arm64_32
>;
1201 callback
= process_linkedit
<arm64_32
>;
1204 callback
= collect_size
<arm64_32
>;
1209 case modeVerboseSlideInfo
:
1210 case modeAcceleratorInfo
:
1212 case modeLocalSymbols
:
1220 fprintf(stderr
, "Error: unrecognized dyld shared cache magic.\n");
1224 __block Results results
;
1225 results
.dependentTargetFound
= false;
1226 int iterateResult
= dyld_shared_cache_iterate(options
.mappedCache
, (uint32_t)cacheLength
,
1227 ^(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
) {
1228 (callback
)(dylibInfo
, segInfo
, options
, results
);
1230 if ( iterateResult
!= 0 ) {
1231 fprintf(stderr
, "Error: malformed shared cache file\n");
1235 if ( options
.mode
== modeLinkEdit
) {
1236 // dump -linkedit information
1237 for (std::map
<uint32_t, const char*>::iterator it
= results
.pageToContent
.begin(); it
!= results
.pageToContent
.end(); ++it
) {
1238 printf("0x%08X %s\n", it
->first
, it
->second
);
1241 else if ( options
.mode
== modeSize
) {
1242 std::sort(results
.textSegments
.begin(), results
.textSegments
.end(), TextInfoSorter());
1243 for (std::vector
<TextInfo
>::iterator it
= results
.textSegments
.begin(); it
!= results
.textSegments
.end(); ++it
) {
1244 printf(" 0x%08llX %s\n", it
->textSize
, it
->path
);
1248 if ( (options
.mode
== modeDependencies
) && options
.dependentsOfPath
&& !results
.dependentTargetFound
) {
1249 fprintf(stderr
, "Error: could not find '%s' in the shared cache at\n %s\n", options
.dependentsOfPath
, sharedCachePath
);