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@ 
  33 #include <sys/syslimits.h> 
  34 #include <mach-o/arch.h> 
  35 #include <mach-o/loader.h> 
  36 #include <mach/mach.h> 
  41 #include "dsc_iterator.h" 
  42 #include "dyld_cache_format.h" 
  43 #include "Architectures.hpp" 
  44 #include "MachOFileAbstraction.hpp" 
  45 #include "CacheFileAbstraction.hpp" 
  60         const char*     dependentsOfPath
; 
  61         const void*     mappedCache
; 
  64     bool                printDylibVersions
; 
  73 struct TextInfoSorter 
{ 
  74         bool operator()(const TextInfo
& left
, const TextInfo
& right
) { 
  75                 return (left
.textSize 
> right
.textSize
); 
  80         std::map
<uint32_t, const char*> pageToContent
; 
  81         uint64_t                                                linkeditBase
; 
  82         bool                                                    dependentTargetFound
; 
  83         std::vector
<TextInfo
>                   textSegments
; 
  89         fprintf(stderr
, "Usage: dyld_shared_cache_util -list [ -uuid ] [-vmaddr] | -dependents <dylib-path> [ -versions ] | -linkedit | -map [ shared-cache-file ] | -slide_info | -info\n"); 
  93 static bool isHaswell() 
  95         // check system is capable of running x86_64h code 
  96         struct host_basic_info info
; 
  97         mach_msg_type_number_t count 
= HOST_BASIC_INFO_COUNT
; 
  98         mach_port_t hostPort 
= mach_host_self(); 
  99         kern_return_t result 
= host_info(hostPort
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
); 
 100         mach_port_deallocate(mach_task_self(), hostPort
); 
 101         if ( result 
!= KERN_SUCCESS 
) 
 103         return ( info
.cpu_subtype 
== CPU_SUBTYPE_X86_64_H 
); 
 108  * Get the path to the native shared cache for this host 
 110 static const char* default_shared_cache_path() { 
 112         return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"i386"; 
 115                 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"x86_64h"; 
 117                 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"x86_64"; 
 118 #elif __ARM_ARCH_5TEJ__  
 119         return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"armv5"; 
 120 #elif __ARM_ARCH_6K__  
 121         return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"armv6"; 
 122 #elif __ARM_ARCH_7K__  
 123         return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"armv7k"; 
 124 #elif __ARM_ARCH_7A__  
 125         return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"armv7"; 
 126 #elif __ARM_ARCH_7F__  
 127         return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"armv7f"; 
 128 #elif __ARM_ARCH_7S__  
 129         return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"armv7s"; 
 131         return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME 
"arm64"; 
 133         #error unsupported architecture 
 137 typedef void (*segment_callback_t
)(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
, 
 138                                                                         const Options
& options
, Results
& results
); 
 143  * List dependencies from the mach-o header at headerAddr 
 144  * in the same format as 'otool -L' 
 146 template <typename A
> 
 147 void print_dependencies(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
,  
 148                                                                                                                                         const Options
& options
, Results
& results
) { 
 149         typedef typename 
A::P           P
; 
 150         typedef typename 
A::P::E        E
; 
 152         if ( strcmp(options
.dependentsOfPath
, dylibInfo
->path
) != 0 )  
 154         if ( strcmp(segInfo
->name
, "__TEXT") != 0 ) 
 157         const macho_dylib_command
<P
>* dylib_cmd
; 
 158         const macho_header
<P
>* mh 
= (const macho_header
<P
>*)dylibInfo
->machHeader
; 
 159         const macho_load_command
<P
>* const cmds 
= (macho_load_command
<P
>*)((uintptr_t)dylibInfo
->machHeader 
+ sizeof(macho_header
<P
>)); 
 160         const uint32_t cmd_count 
= mh
->ncmds(); 
 161         const macho_load_command
<P
>* cmd 
= cmds
; 
 162         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 163                 switch ( cmd
->cmd() ) { 
 166                         case LC_REEXPORT_DYLIB
: 
 167                         case LC_LOAD_WEAK_DYLIB
: 
 168                         case LC_LOAD_UPWARD_DYLIB
: 
 169                                 dylib_cmd 
= (macho_dylib_command
<P
>*)cmd
; 
 170                                 if ( options
.printDylibVersions 
) { 
 171                                         uint32_t compat_vers 
= dylib_cmd
->compatibility_version(); 
 172                                         uint32_t current_vers 
= dylib_cmd
->current_version(); 
 173                                         printf("\t%s", dylib_cmd
->name()); 
 174                                         if ( compat_vers 
!= 0xFFFFFFFF ) { 
 175                                                 printf("(compatibility version %u.%u.%u, current version %u.%u.%u)\n",  
 177                                                    (compat_vers 
>> 8) & 0xff, 
 178                                                    (compat_vers
) & 0xff, 
 179                                                    (current_vers 
>> 16), 
 180                                                    (current_vers 
>> 8) & 0xff, 
 181                                                    (current_vers
) & 0xff); 
 188                                         printf("\t%s\n", dylib_cmd
->name()); 
 192                 cmd 
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize()); 
 194         results
.dependentTargetFound 
= true; 
 198  * Print out a dylib from the shared cache, optionally including the UUID or unslid load address 
 200 template <typename A
> 
 201 void print_list(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
,  
 202                                                                                                                                                 const Options
& options
, Results
& results
)  
 204         if ( strcmp(segInfo
->name
, "__TEXT") != 0 ) 
 207         if ( options
.printVMAddrs 
) 
 208                 printf("0x%08llX ", segInfo
->address
); 
 209         if ( options
.printInodes 
) 
 210                 printf("0x%08llX 0x%08llX ", dylibInfo
->inode
, dylibInfo
->modTime
); 
 211         if ( options
.printUUIDs 
) { 
 212                 if ( dylibInfo
->uuid 
!= NULL 
) { 
 213                         const uint8_t* uuid 
= (uint8_t*)dylibInfo
->uuid
;; 
 214                         printf("<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X> ", 
 215                                 uuid
[0],  uuid
[1],  uuid
[2],  uuid
[3],   
 216                                         uuid
[4],  uuid
[5],  uuid
[6],  uuid
[7],  
 217                                 uuid
[8],  uuid
[9],  uuid
[10], uuid
[11],  
 218                                         uuid
[12], uuid
[13], uuid
[14], uuid
[15]); 
 221                         printf("<     no uuid in dylib               > "); 
 223         if ( dylibInfo
->isAlias 
) 
 224                 printf("[alias] %s\n", dylibInfo
->path
); 
 226                 printf("%s\n", dylibInfo
->path
); 
 230 template <typename A
> 
 231 void collect_size(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
,  
 232                                                                                                                                                 const Options
& options
, Results
& results
)  
 234         if ( strcmp(segInfo
->name
, "__TEXT") != 0 ) 
 236         if ( dylibInfo
->isAlias 
) 
 240         info
.textSize 
= segInfo
->fileSize
; 
 241         info
.path 
= dylibInfo
->path
; 
 242         results
.textSegments
.push_back(info
); 
 243         size_t size 
= segInfo
->fileSize
; 
 249 static void add_linkedit(uint32_t pageStart
, uint32_t pageEnd
, const char* message
, Results
& results
)  
 251         for (uint32_t p 
= pageStart
; p 
<= pageEnd
; p 
+= 4096) { 
 252                 std::map
<uint32_t, const char*>::iterator pos 
= results
.pageToContent
.find(p
); 
 253                 if ( pos 
== results
.pageToContent
.end() ) { 
 254                         results
.pageToContent
[p
] = strdup(message
); 
 257                         const char* oldMessage 
= pos
->second
; 
 259                         asprintf(&newMesssage
, "%s, %s", oldMessage
, message
); 
 260                         results
.pageToContent
[p
] = newMesssage
; 
 261                         ::free((void*)oldMessage
); 
 268  * get LINKEDIT info for dylib 
 270 template <typename A
> 
 271 void process_linkedit(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
,  
 272                                                                                                                                                         const Options
& options
, Results
& results
) { 
 273         typedef typename 
A::P           P
; 
 274         typedef typename 
A::P::E        E
; 
 275         // filter out symlinks  
 276         if ( dylibInfo
->isAlias 
) 
 278         const macho_header
<P
>* mh 
= (const macho_header
<P
>*)dylibInfo
->machHeader
; 
 279         uint32_t ncmds 
= mh
->ncmds(); 
 280         const macho_load_command
<P
>* const cmds 
= (macho_load_command
<P
>*)((long)mh 
+ sizeof(macho_header
<P
>)); 
 281         const macho_load_command
<P
>* cmd 
= cmds
; 
 282         for (uint32_t i 
= 0; i 
< ncmds
; i
++) { 
 283                 if ( cmd
->cmd() == LC_DYLD_INFO_ONLY 
) { 
 284                         macho_dyld_info_command
<P
>* dyldInfo 
= (macho_dyld_info_command
<P
>*)cmd
; 
 286                         const char* shortName 
= strrchr(dylibInfo
->path
, '/') + 1; 
 287                         // add export trie info 
 288                         if ( dyldInfo
->export_size() != 0 ) { 
 289                                 //printf("export_off=0x%X\n", dyldInfo->export_off()); 
 290                                 uint32_t exportPageOffsetStart 
= dyldInfo
->export_off() & (-4096); 
 291                                 uint32_t exportPageOffsetEnd 
= (dyldInfo
->export_off() + dyldInfo
->export_size()) & (-4096); 
 292                                 sprintf(message
, "exports from %s", shortName
); 
 293                                 add_linkedit(exportPageOffsetStart
, exportPageOffsetEnd
, message
, results
); 
 296                         if ( dyldInfo
->bind_size() != 0 ) { 
 297                                 uint32_t bindPageOffsetStart 
= dyldInfo
->bind_off() & (-4096); 
 298                                 uint32_t bindPageOffsetEnd 
= (dyldInfo
->bind_off() + dyldInfo
->bind_size()) & (-4096); 
 299                                 sprintf(message
, "bindings from %s", shortName
); 
 300                                 add_linkedit(bindPageOffsetStart
, bindPageOffsetEnd
, message
, results
); 
 302                         // add lazy binding info 
 303                         if ( dyldInfo
->lazy_bind_size() != 0 ) { 
 304                                 uint32_t lazybindPageOffsetStart 
= dyldInfo
->lazy_bind_off() & (-4096); 
 305                                 uint32_t lazybindPageOffsetEnd 
= (dyldInfo
->lazy_bind_off() + dyldInfo
->lazy_bind_size()) & (-4096); 
 306                                 sprintf(message
, "lazy bindings from %s", shortName
); 
 307                                 add_linkedit(lazybindPageOffsetStart
, lazybindPageOffsetEnd
, message
, results
); 
 309                         // add weak binding info 
 310                         if ( dyldInfo
->weak_bind_size() != 0 ) { 
 311                                 uint32_t weakbindPageOffsetStart 
= dyldInfo
->weak_bind_off() & (-4096); 
 312                                 uint32_t weakbindPageOffsetEnd 
= (dyldInfo
->weak_bind_off() + dyldInfo
->weak_bind_size()) & (-4096); 
 313                                 sprintf(message
, "weak bindings from %s", shortName
); 
 314                                 add_linkedit(weakbindPageOffsetStart
, weakbindPageOffsetEnd
, message
, results
); 
 317                 cmd 
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize()); 
 323  * Print out a .map file similar to what update_dyld_shared_cache created when the cache file was built 
 325 template <typename A
> 
 326 void print_map(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
, const Options
& options
, Results
& results
) { 
 327         if ( !dylibInfo
->isAlias 
) 
 328                 printf("0x%08llX - 0x%08llX %s %s\n", segInfo
->address
, segInfo
->address 
+ segInfo
->fileSize
, segInfo
->name
, dylibInfo
->path
); 
 332 static void checkMode(Mode mode
) { 
 333         if ( mode 
!= modeNone 
) { 
 334                 fprintf(stderr
, "Error: select one of: -list, -dependents, -info, -slide_info, -linkedit, -map, or -size\n"); 
 340 int main (int argc
, const char* argv
[]) { 
 342         const char* sharedCachePath 
= default_shared_cache_path(); 
 345         options
.mode 
= modeNone
; 
 346     options
.printUUIDs 
= false; 
 347         options
.printVMAddrs 
= false; 
 348     options
.printDylibVersions 
= false; 
 349         options
.printInodes 
= false; 
 350     options
.dependentsOfPath 
= NULL
; 
 352     for (uint32_t i 
= 1; i 
< argc
; i
++) { 
 353         const char* opt 
= argv
[i
]; 
 355             if (strcmp(opt
, "-list") == 0) { 
 356                                 checkMode(options
.mode
); 
 357                                 options
.mode 
= modeList
; 
 359                         else if (strcmp(opt
, "-dependents") == 0) { 
 360                                 checkMode(options
.mode
); 
 361                                 options
.mode 
= modeDependencies
; 
 362                                 options
.dependentsOfPath 
= argv
[++i
]; 
 364                     fprintf(stderr
, "Error: option -depdendents requires an argument\n"); 
 369                         else if (strcmp(opt
, "-linkedit") == 0) { 
 370                                 checkMode(options
.mode
); 
 371                                 options
.mode 
= modeLinkEdit
; 
 373                         else if (strcmp(opt
, "-info") == 0) { 
 374                                 checkMode(options
.mode
); 
 375                                 options
.mode 
= modeInfo
; 
 377                         else if (strcmp(opt
, "-slide_info") == 0) { 
 378                                 checkMode(options
.mode
); 
 379                                 options
.mode 
= modeSlideInfo
; 
 381                         else if (strcmp(opt
, "-map") == 0) { 
 382                                 checkMode(options
.mode
); 
 383                                 options
.mode 
= modeMap
; 
 385                         else if (strcmp(opt
, "-size") == 0) { 
 386                                 checkMode(options
.mode
); 
 387                                 options
.mode 
= modeSize
; 
 389                         else if (strcmp(opt
, "-uuid") == 0) { 
 390                 options
.printUUIDs 
= true; 
 392                         else if (strcmp(opt
, "-inode") == 0) { 
 393                 options
.printInodes 
= true; 
 395                         else if (strcmp(opt
, "-versions") == 0) { 
 396                 options
.printDylibVersions 
= true; 
 398                         else if (strcmp(opt
, "-vmaddr") == 0) { 
 399                                 options
.printVMAddrs 
= true; 
 402                 fprintf(stderr
, "Error: unrecognized option %s\n", opt
); 
 408             sharedCachePath 
= opt
; 
 412         if ( options
.mode 
== modeNone 
) { 
 413                 fprintf(stderr
, "Error: select one of -list, -dependents, -info, -linkedit, or -map\n"); 
 418         if ( options
.mode 
!= modeSlideInfo 
) { 
 419                 if ( options
.printUUIDs 
&& (options
.mode 
!= modeList
) ) 
 420                         fprintf(stderr
, "Warning: -uuid option ignored outside of -list mode\n"); 
 422                 if ( options
.printVMAddrs 
&& (options
.mode 
!= modeList
) ) 
 423                         fprintf(stderr
, "Warning: -vmaddr option ignored outside of -list mode\n"); 
 425                 if ( options
.printDylibVersions 
&& (options
.mode 
!= modeDependencies
) ) 
 426                         fprintf(stderr
, "Warning: -versions option ignored outside of -dependents mode\n"); 
 428                 if ( (options
.mode 
== modeDependencies
) && (options
.dependentsOfPath 
== NULL
) ) { 
 429                         fprintf(stderr
, "Error: -dependents given, but no dylib path specified\n"); 
 436         if ( ::stat(sharedCachePath
, &statbuf
) == -1 ) { 
 437                 fprintf(stderr
, "Error: stat() failed for dyld shared cache at %s, errno=%d\n", sharedCachePath
, errno
); 
 441         int cache_fd 
= ::open(sharedCachePath
, O_RDONLY
); 
 442         if ( cache_fd 
< 0 ) { 
 443                 fprintf(stderr
, "Error: open() failed for shared cache file at %s, errno=%d\n", sharedCachePath
, errno
); 
 446         options
.mappedCache 
= ::mmap(NULL
, statbuf
.st_size
, PROT_READ
, MAP_PRIVATE
, cache_fd
, 0); 
 447         if (options
.mappedCache 
== MAP_FAILED
) { 
 448                 fprintf(stderr
, "Error: mmap() for shared cache at %s failed, errno=%d\n", sharedCachePath
, errno
); 
 452         if ( options
.mode 
== modeSlideInfo 
) { 
 453                 const dyldCacheHeader
<LittleEndian
>* header 
= (dyldCacheHeader
<LittleEndian
>*)options
.mappedCache
; 
 454                 if ( header
->slideInfoOffset() == 0 ) { 
 455                         fprintf(stderr
, "Error: dyld shared cache does not contain slide info\n"); 
 458                 const dyldCacheFileMapping
<LittleEndian
>* mappings 
= (dyldCacheFileMapping
<LittleEndian
>*)((char*)options
.mappedCache 
+ header
->mappingOffset()); 
 459                 const dyldCacheFileMapping
<LittleEndian
>* dataMapping 
= &mappings
[1]; 
 460                 uint64_t dataStartAddress 
= dataMapping
->address(); 
 461                 uint64_t dataSize 
= dataMapping
->size(); 
 462                 const dyldCacheSlideInfo
<LittleEndian
>* slideInfoHeader 
= (dyldCacheSlideInfo
<LittleEndian
>*)((char*)options
.mappedCache
+header
->slideInfoOffset()); 
 463                 printf("slide info version=%d\n", slideInfoHeader
->version()); 
 464                 printf("toc_count=%d, data page count=%lld\n", slideInfoHeader
->toc_count(), dataSize
/4096); 
 465                 const dyldCacheSlideInfoEntry
* entries 
= (dyldCacheSlideInfoEntry
*)((char*)slideInfoHeader 
+ slideInfoHeader
->entries_offset()); 
 466                 for(int i
=0; i 
< slideInfoHeader
->toc_count(); ++i
) { 
 467                         printf("0x%08llX: [% 5d,% 5d] ", dataStartAddress 
+ i
*4096, i
, slideInfoHeader
->toc(i
)); 
 468                         const dyldCacheSlideInfoEntry
* entry 
= &entries
[slideInfoHeader
->toc(i
)]; 
 469                         for(int j
=0; j 
< slideInfoHeader
->entries_size(); ++j
) 
 470                                 printf("%02X", entry
->bits
[j
]); 
 474         else if ( options
.mode 
== modeInfo 
) { 
 475                 const dyldCacheHeader
<LittleEndian
>* header 
= (dyldCacheHeader
<LittleEndian
>*)options
.mappedCache
; 
 477                 if ( header
->mappingOffset() >= 0x68 ) { 
 478                         const uint8_t* uuid 
= header
->uuid(); 
 479                         printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", 
 480                                    uuid
[0],  uuid
[1],  uuid
[2],  uuid
[3], 
 481                                    uuid
[4],  uuid
[5],  uuid
[6],  uuid
[7], 
 482                                    uuid
[8],  uuid
[9],  uuid
[10], uuid
[11], 
 483                                    uuid
[12], uuid
[13], uuid
[14], uuid
[15]); 
 488                 printf("image count: %u\n", header
->imagesCount()); 
 489                 printf("mappings:\n"); 
 490                 const dyldCacheFileMapping
<LittleEndian
>* mappings 
= (dyldCacheFileMapping
<LittleEndian
>*)((char*)options
.mappedCache 
+ header
->mappingOffset()); 
 491                 for (uint32_t i
=0; i 
< header
->mappingCount(); ++i
) { 
 492                         if ( mappings
[i
].init_prot() & VM_PROT_EXECUTE 
) 
 493                                 printf("    __TEXT      %3lluMB,  0x%08llX -> 0x%08llX\n", mappings
[i
].size()/(1024*1024), mappings
[i
].address(), mappings
[i
].address() + mappings
[i
].size()); 
 494                         else if ( mappings
[i
]. init_prot() & VM_PROT_WRITE 
) 
 495                                 printf("    __DATA      %3lluMB,  0x%08llX -> 0x%08llX\n", mappings
[i
].size()/(1024*1024), mappings
[i
].address(), mappings
[i
].address() + mappings
[i
].size()); 
 496                         else if ( mappings
[i
].init_prot() & VM_PROT_READ 
) 
 497                                 printf("    __LINKEDIT  %3lluMB,  0x%08llX -> 0x%08llX\n", mappings
[i
].size()/(1024*1024), mappings
[i
].address(), mappings
[i
].address() + mappings
[i
].size()); 
 499                 if ( header
->codeSignatureOffset() != 0 ) { 
 500                         uint64_t size 
= statbuf
.st_size 
- header
->codeSignatureOffset();  
 501                         uint64_t csAddr 
= mappings
[header
->mappingCount()-1].address() + mappings
[header
->mappingCount()-1].size(); 
 502                                 printf("    code sign   %3lluMB,  0x%08llX -> 0x%08llX\n", size
/(1024*1024), csAddr
, csAddr 
+ size
); 
 506                 segment_callback_t callback
; 
 507                 if ( strcmp((char*)options
.mappedCache
, "dyld_v1    i386") == 0 ) { 
 508                         switch ( options
.mode 
) { 
 510                                         callback 
= print_list
<x86
>; 
 513                                         callback 
= print_map
<x86
>; 
 515                                 case modeDependencies
: 
 516                                         callback 
= print_dependencies
<x86
>; 
 519                                         callback 
= process_linkedit
<x86
>; 
 522                                         callback 
= collect_size
<x86
>; 
 530                 else if (  (strcmp((char*)options
.mappedCache
, "dyld_v1  x86_64") == 0) 
 531                                 || (strcmp((char*)options
.mappedCache
, "dyld_v1 x86_64h") == 0) ) { 
 532                         switch ( options
.mode 
) { 
 534                                         callback 
= print_list
<x86_64
>; 
 537                                         callback 
= print_map
<x86_64
>; 
 539                                 case modeDependencies
: 
 540                                         callback 
= print_dependencies
<x86_64
>; 
 543                                         callback 
= process_linkedit
<x86_64
>; 
 546                                         callback 
= collect_size
<x86_64
>; 
 554                 else if ( (strncmp((char*)options
.mappedCache
, "dyld_v1   armv", 14) == 0)  
 555                            || (strncmp((char*)options
.mappedCache
, "dyld_v1  armv", 13) == 0) ) { 
 556                         switch ( options
.mode 
) { 
 558                                         callback 
= print_list
<arm
>; 
 561                                         callback 
= print_map
<arm
>; 
 563                                 case modeDependencies
: 
 564                                         callback 
= print_dependencies
<arm
>; 
 567                                         callback 
= process_linkedit
<arm
>; 
 570                                         callback 
= collect_size
<arm
>; 
 578                 else if ( strcmp((char*)options
.mappedCache
, "dyld_v1   arm64") == 0 ) { 
 579                         switch ( options
.mode 
) { 
 581                                         callback 
= print_list
<arm64
>; 
 584                                         callback 
= print_map
<arm64
>; 
 586                                 case modeDependencies
: 
 587                                         callback 
= print_dependencies
<arm64
>; 
 590                                         callback 
= process_linkedit
<arm64
>; 
 593                                         callback 
= collect_size
<arm64
>; 
 602                         fprintf(stderr
, "Error: unrecognized dyld shared cache magic.\n"); 
 606                 __block Results results
; 
 607                 results
.dependentTargetFound 
= false; 
 608                 int iterateResult 
= dyld_shared_cache_iterate(options
.mappedCache
, (uint32_t)statbuf
.st_size
,  
 609                                                                                    ^(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo 
) { 
 610                                                                                            (callback
)(dylibInfo
, segInfo
, options
, results
); 
 612                 if ( iterateResult 
!= 0 ) { 
 613                         fprintf(stderr
, "Error: malformed shared cache file\n"); 
 617                 if ( options
.mode 
== modeLinkEdit 
) { 
 618                         // dump -linkedit information 
 619                         for (std::map
<uint32_t, const char*>::iterator it 
= results
.pageToContent
.begin(); it 
!= results
.pageToContent
.end(); ++it
) { 
 620                                 printf("0x%08X %s\n", it
->first
, it
->second
); 
 623                 else if ( options
.mode 
== modeSize 
) { 
 624                         std::sort(results
.textSegments
.begin(), results
.textSegments
.end(), TextInfoSorter());  
 625                         for (std::vector
<TextInfo
>::iterator it 
= results
.textSegments
.begin(); it 
!= results
.textSegments
.end(); ++it
) { 
 626                                 printf(" 0x%08llX  %s\n", it
->textSize
, it
->path
); 
 630                 if ( (options
.mode 
== modeDependencies
) && options
.dependentsOfPath 
&& !results
.dependentTargetFound
) { 
 631                         fprintf(stderr
, "Error: could not find '%s' in the shared cache at\n  %s\n", options
.dependentsOfPath
, sharedCachePath
);