]> git.saurik.com Git - apple/dyld.git/blame - launch-cache/dyld_shared_cache_util.cpp
dyld-360.18.tar.gz
[apple/dyld.git] / launch-cache / dyld_shared_cache_util.cpp
CommitLineData
412ebb8e
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
2fd3f4e8 3 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
412ebb8e
A
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <stdio.h>
26#include <unistd.h>
27#include <sys/stat.h>
28#include <string.h>
29#include <fcntl.h>
30#include <stdlib.h>
31#include <errno.h>
32#include <sys/mman.h>
33#include <sys/syslimits.h>
34#include <mach-o/arch.h>
35#include <mach-o/loader.h>
19894a12 36#include <mach/mach.h>
412ebb8e 37
412ebb8e 38#include <map>
19894a12 39#include <vector>
412ebb8e
A
40
41#include "dsc_iterator.h"
42#include "dyld_cache_format.h"
43#include "Architectures.hpp"
44#include "MachOFileAbstraction.hpp"
45#include "CacheFileAbstraction.hpp"
46
2fd3f4e8
A
47enum Mode {
48 modeNone,
49 modeList,
50 modeMap,
51 modeDependencies,
52 modeSlideInfo,
53 modeLinkEdit,
19894a12
A
54 modeInfo,
55 modeSize
2fd3f4e8 56};
412ebb8e 57
2fd3f4e8
A
58struct Options {
59 Mode mode;
60 const char* dependentsOfPath;
61 const void* mappedCache;
62 bool printUUIDs;
63 bool printVMAddrs;
64 bool printDylibVersions;
19894a12
A
65 bool printInodes;
66};
67
68struct TextInfo {
69 uint64_t textSize;
70 const char* path;
71};
72
73struct TextInfoSorter {
74 bool operator()(const TextInfo& left, const TextInfo& right) {
75 return (left.textSize > right.textSize);
76 }
2fd3f4e8 77};
412ebb8e 78
2fd3f4e8
A
79struct Results {
80 std::map<uint32_t, const char*> pageToContent;
81 uint64_t linkeditBase;
82 bool dependentTargetFound;
19894a12 83 std::vector<TextInfo> textSegments;
412ebb8e
A
84};
85
2fd3f4e8
A
86
87
412ebb8e 88void usage() {
2fd3f4e8 89 fprintf(stderr, "Usage: dyld_shared_cache_util -list [ -uuid ] [-vmaddr] | -dependents <dylib-path> [ -versions ] | -linkedit | -map [ shared-cache-file ] | -slide_info | -info\n");
412ebb8e
A
90}
91
19894a12
A
92#if __x86_64__
93static bool isHaswell()
94{
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 )
102 return false;
103 return ( info.cpu_subtype == CPU_SUBTYPE_X86_64_H );
104}
105#endif
106
412ebb8e
A
107/*
108 * Get the path to the native shared cache for this host
109 */
110static const char* default_shared_cache_path() {
111#if __i386__
112 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "i386";
113#elif __x86_64__
19894a12
A
114 if ( isHaswell() )
115 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "x86_64h";
116 else
117 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "x86_64";
412ebb8e
A
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";
19894a12
A
122#elif __ARM_ARCH_7K__
123 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7k";
412ebb8e
A
124#elif __ARM_ARCH_7A__
125 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7";
832b6fce
A
126#elif __ARM_ARCH_7F__
127 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7f";
2fd3f4e8
A
128#elif __ARM_ARCH_7S__
129 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7s";
19894a12
A
130#elif __arm64__
131 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "arm64";
412ebb8e
A
132#else
133 #error unsupported architecture
134#endif
135}
136
2fd3f4e8
A
137typedef void (*segment_callback_t)(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
138 const Options& options, Results& results);
139
140
412ebb8e
A
141
142/*
143 * List dependencies from the mach-o header at headerAddr
144 * in the same format as 'otool -L'
145 */
146template <typename A>
2fd3f4e8
A
147void print_dependencies(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
148 const Options& options, Results& results) {
412ebb8e
A
149 typedef typename A::P P;
150 typedef typename A::P::E E;
151
2fd3f4e8
A
152 if ( strcmp(options.dependentsOfPath, dylibInfo->path) != 0 )
153 return;
154 if ( strcmp(segInfo->name, "__TEXT") != 0 )
155 return;
156
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() ) {
164 case LC_LOAD_DYLIB:
165 case LC_ID_DYLIB:
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",
176 (compat_vers >> 16),
177 (compat_vers >> 8) & 0xff,
178 (compat_vers) & 0xff,
179 (current_vers >> 16),
180 (current_vers >> 8) & 0xff,
181 (current_vers) & 0xff);
182 }
183 else {
184 printf("\n");
185 }
186 }
187 else {
188 printf("\t%s\n", dylib_cmd->name());
189 }
190 break;
412ebb8e 191 }
2fd3f4e8 192 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
412ebb8e 193 }
2fd3f4e8 194 results.dependentTargetFound = true;
412ebb8e
A
195}
196
197/*
2fd3f4e8 198 * Print out a dylib from the shared cache, optionally including the UUID or unslid load address
412ebb8e
A
199 */
200template <typename A>
2fd3f4e8
A
201void print_list(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
202 const Options& options, Results& results)
203{
204 if ( strcmp(segInfo->name, "__TEXT") != 0 )
205 return;
412ebb8e 206
2fd3f4e8
A
207 if ( options.printVMAddrs )
208 printf("0x%08llX ", segInfo->address);
19894a12
A
209 if ( options.printInodes )
210 printf("0x%08llX 0x%08llX ", dylibInfo->inode, dylibInfo->modTime);
2fd3f4e8
A
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]);
219 }
412ebb8e
A
220 else
221 printf("< no uuid in dylib > ");
222 }
2fd3f4e8
A
223 if ( dylibInfo->isAlias )
224 printf("[alias] %s\n", dylibInfo->path);
225 else
226 printf("%s\n", dylibInfo->path);
412ebb8e
A
227}
228
229
19894a12
A
230template <typename A>
231void collect_size(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
232 const Options& options, Results& results)
233{
234 if ( strcmp(segInfo->name, "__TEXT") != 0 )
235 return;
236 if ( dylibInfo->isAlias )
237 return;
238
239 TextInfo info;
240 info.textSize = segInfo->fileSize;
241 info.path = dylibInfo->path;
242 results.textSegments.push_back(info);
243 size_t size = segInfo->fileSize;
244}
245
246
412ebb8e
A
247
248
2fd3f4e8 249static void add_linkedit(uint32_t pageStart, uint32_t pageEnd, const char* message, Results& results)
412ebb8e
A
250{
251 for (uint32_t p = pageStart; p <= pageEnd; p += 4096) {
2fd3f4e8
A
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);
412ebb8e
A
255 }
256 else {
2fd3f4e8 257 const char* oldMessage = pos->second;
412ebb8e
A
258 char* newMesssage;
259 asprintf(&newMesssage, "%s, %s", oldMessage, message);
2fd3f4e8
A
260 results.pageToContent[p] = newMesssage;
261 ::free((void*)oldMessage);
412ebb8e
A
262 }
263 }
264}
265
266
267/*
268 * get LINKEDIT info for dylib
269 */
270template <typename A>
2fd3f4e8
A
271void process_linkedit(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
272 const Options& options, Results& results) {
412ebb8e
A
273 typedef typename A::P P;
274 typedef typename A::P::E E;
2fd3f4e8
A
275 // filter out symlinks
276 if ( dylibInfo->isAlias )
412ebb8e 277 return;
2fd3f4e8 278 const macho_header<P>* mh = (const macho_header<P>*)dylibInfo->machHeader;
412ebb8e
A
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;
285 char message[1000];
2fd3f4e8 286 const char* shortName = strrchr(dylibInfo->path, '/') + 1;
412ebb8e
A
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);
2fd3f4e8 293 add_linkedit(exportPageOffsetStart, exportPageOffsetEnd, message, results);
412ebb8e
A
294 }
295 // add binding info
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);
2fd3f4e8 300 add_linkedit(bindPageOffsetStart, bindPageOffsetEnd, message, results);
412ebb8e
A
301 }
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);
2fd3f4e8 307 add_linkedit(lazybindPageOffsetStart, lazybindPageOffsetEnd, message, results);
412ebb8e
A
308 }
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);
2fd3f4e8 314 add_linkedit(weakbindPageOffsetStart, weakbindPageOffsetEnd, message, results);
412ebb8e
A
315 }
316 }
317 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
318 }
319}
320
321
412ebb8e 322/*
2fd3f4e8 323 * Print out a .map file similar to what update_dyld_shared_cache created when the cache file was built
412ebb8e
A
324 */
325template <typename A>
2fd3f4e8
A
326void 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);
412ebb8e
A
329}
330
331
2fd3f4e8
A
332static void checkMode(Mode mode) {
333 if ( mode != modeNone ) {
19894a12 334 fprintf(stderr, "Error: select one of: -list, -dependents, -info, -slide_info, -linkedit, -map, or -size\n");
2fd3f4e8
A
335 usage();
336 exit(1);
337 }
338}
339
340int main (int argc, const char* argv[]) {
412ebb8e 341
2fd3f4e8 342 const char* sharedCachePath = default_shared_cache_path();
412ebb8e 343
2fd3f4e8
A
344 Options options;
345 options.mode = modeNone;
346 options.printUUIDs = false;
347 options.printVMAddrs = false;
348 options.printDylibVersions = false;
19894a12 349 options.printInodes = false;
2fd3f4e8 350 options.dependentsOfPath = NULL;
412ebb8e 351
2fd3f4e8
A
352 for (uint32_t i = 1; i < argc; i++) {
353 const char* opt = argv[i];
412ebb8e
A
354 if (opt[0] == '-') {
355 if (strcmp(opt, "-list") == 0) {
2fd3f4e8
A
356 checkMode(options.mode);
357 options.mode = modeList;
358 }
359 else if (strcmp(opt, "-dependents") == 0) {
360 checkMode(options.mode);
361 options.mode = modeDependencies;
362 options.dependentsOfPath = argv[++i];
363 if ( i >= argc ) {
412ebb8e
A
364 fprintf(stderr, "Error: option -depdendents requires an argument\n");
365 usage();
366 exit(1);
367 }
2fd3f4e8
A
368 }
369 else if (strcmp(opt, "-linkedit") == 0) {
370 checkMode(options.mode);
371 options.mode = modeLinkEdit;
372 }
373 else if (strcmp(opt, "-info") == 0) {
374 checkMode(options.mode);
375 options.mode = modeInfo;
376 }
377 else if (strcmp(opt, "-slide_info") == 0) {
378 checkMode(options.mode);
379 options.mode = modeSlideInfo;
380 }
381 else if (strcmp(opt, "-map") == 0) {
382 checkMode(options.mode);
383 options.mode = modeMap;
19894a12
A
384 }
385 else if (strcmp(opt, "-size") == 0) {
386 checkMode(options.mode);
387 options.mode = modeSize;
2fd3f4e8
A
388 }
389 else if (strcmp(opt, "-uuid") == 0) {
390 options.printUUIDs = true;
19894a12
A
391 }
392 else if (strcmp(opt, "-inode") == 0) {
393 options.printInodes = true;
2fd3f4e8
A
394 }
395 else if (strcmp(opt, "-versions") == 0) {
396 options.printDylibVersions = true;
397 }
398 else if (strcmp(opt, "-vmaddr") == 0) {
399 options.printVMAddrs = true;
400 }
401 else {
412ebb8e
A
402 fprintf(stderr, "Error: unrecognized option %s\n", opt);
403 usage();
404 exit(1);
405 }
2fd3f4e8
A
406 }
407 else {
408 sharedCachePath = opt;
412ebb8e
A
409 }
410 }
411
2fd3f4e8
A
412 if ( options.mode == modeNone ) {
413 fprintf(stderr, "Error: select one of -list, -dependents, -info, -linkedit, or -map\n");
414 usage();
415 exit(1);
416 }
412ebb8e 417
2fd3f4e8
A
418 if ( options.mode != modeSlideInfo ) {
419 if ( options.printUUIDs && (options.mode != modeList) )
412ebb8e 420 fprintf(stderr, "Warning: -uuid option ignored outside of -list mode\n");
2fd3f4e8
A
421
422 if ( options.printVMAddrs && (options.mode != modeList) )
412ebb8e 423 fprintf(stderr, "Warning: -vmaddr option ignored outside of -list mode\n");
2fd3f4e8
A
424
425 if ( options.printDylibVersions && (options.mode != modeDependencies) )
412ebb8e
A
426 fprintf(stderr, "Warning: -versions option ignored outside of -dependents mode\n");
427
2fd3f4e8 428 if ( (options.mode == modeDependencies) && (options.dependentsOfPath == NULL) ) {
412ebb8e
A
429 fprintf(stderr, "Error: -dependents given, but no dylib path specified\n");
430 usage();
431 exit(1);
432 }
433 }
2fd3f4e8
A
434
435 struct stat statbuf;
436 if ( ::stat(sharedCachePath, &statbuf) == -1 ) {
437 fprintf(stderr, "Error: stat() failed for dyld shared cache at %s, errno=%d\n", sharedCachePath, errno);
412ebb8e
A
438 exit(1);
439 }
440
2fd3f4e8
A
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);
412ebb8e
A
444 exit(1);
445 }
2fd3f4e8
A
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);
412ebb8e
A
449 exit(1);
450 }
451
2fd3f4e8
A
452 if ( options.mode == modeSlideInfo ) {
453 const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)options.mappedCache;
412ebb8e
A
454 if ( header->slideInfoOffset() == 0 ) {
455 fprintf(stderr, "Error: dyld shared cache does not contain slide info\n");
456 exit(1);
457 }
2fd3f4e8 458 const dyldCacheFileMapping<LittleEndian>* mappings = (dyldCacheFileMapping<LittleEndian>*)((char*)options.mappedCache + header->mappingOffset());
412ebb8e
A
459 const dyldCacheFileMapping<LittleEndian>* dataMapping = &mappings[1];
460 uint64_t dataStartAddress = dataMapping->address();
461 uint64_t dataSize = dataMapping->size();
2fd3f4e8 462 const dyldCacheSlideInfo<LittleEndian>* slideInfoHeader = (dyldCacheSlideInfo<LittleEndian>*)((char*)options.mappedCache+header->slideInfoOffset());
412ebb8e
A
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]);
471 printf("\n");
472 }
2fd3f4e8
A
473 }
474 else if ( options.mode == modeInfo ) {
475 const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)options.mappedCache;
476 printf("uuid: ");
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]);
484 }
485 else {
486 printf("n/a\n");
487 }
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 )
19894a12 493 printf(" __TEXT %3lluMB, 0x%08llX -> 0x%08llX\n", mappings[i].size()/(1024*1024), mappings[i].address(), mappings[i].address() + mappings[i].size());
2fd3f4e8 494 else if ( mappings[i]. init_prot() & VM_PROT_WRITE )
19894a12 495 printf(" __DATA %3lluMB, 0x%08llX -> 0x%08llX\n", mappings[i].size()/(1024*1024), mappings[i].address(), mappings[i].address() + mappings[i].size());
2fd3f4e8 496 else if ( mappings[i].init_prot() & VM_PROT_READ )
19894a12
A
497 printf(" __LINKEDIT %3lluMB, 0x%08llX -> 0x%08llX\n", mappings[i].size()/(1024*1024), mappings[i].address(), mappings[i].address() + mappings[i].size());
498 }
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);
2fd3f4e8 503 }
412ebb8e
A
504 }
505 else {
506 segment_callback_t callback;
2fd3f4e8
A
507 if ( strcmp((char*)options.mappedCache, "dyld_v1 i386") == 0 ) {
508 switch ( options.mode ) {
509 case modeList:
510 callback = print_list<x86>;
511 break;
512 case modeMap:
513 callback = print_map<x86>;
514 break;
515 case modeDependencies:
516 callback = print_dependencies<x86>;
517 break;
518 case modeLinkEdit:
519 callback = process_linkedit<x86>;
520 break;
19894a12
A
521 case modeSize:
522 callback = collect_size<x86>;
523 break;
2fd3f4e8
A
524 case modeNone:
525 case modeInfo:
526 case modeSlideInfo:
527 break;
528 }
529 }
19894a12
A
530 else if ( (strcmp((char*)options.mappedCache, "dyld_v1 x86_64") == 0)
531 || (strcmp((char*)options.mappedCache, "dyld_v1 x86_64h") == 0) ) {
2fd3f4e8
A
532 switch ( options.mode ) {
533 case modeList:
534 callback = print_list<x86_64>;
535 break;
536 case modeMap:
537 callback = print_map<x86_64>;
538 break;
539 case modeDependencies:
540 callback = print_dependencies<x86_64>;
541 break;
542 case modeLinkEdit:
543 callback = process_linkedit<x86_64>;
544 break;
19894a12
A
545 case modeSize:
546 callback = collect_size<x86_64>;
547 break;
2fd3f4e8
A
548 case modeNone:
549 case modeInfo:
550 case modeSlideInfo:
551 break;
552 }
553 }
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 ) {
557 case modeList:
558 callback = print_list<arm>;
559 break;
560 case modeMap:
561 callback = print_map<arm>;
562 break;
563 case modeDependencies:
564 callback = print_dependencies<arm>;
565 break;
566 case modeLinkEdit:
567 callback = process_linkedit<arm>;
568 break;
19894a12
A
569 case modeSize:
570 callback = collect_size<arm>;
571 break;
572 case modeNone:
573 case modeInfo:
574 case modeSlideInfo:
575 break;
576 }
577 }
578 else if ( strcmp((char*)options.mappedCache, "dyld_v1 arm64") == 0 ) {
579 switch ( options.mode ) {
580 case modeList:
581 callback = print_list<arm64>;
582 break;
583 case modeMap:
584 callback = print_map<arm64>;
585 break;
586 case modeDependencies:
587 callback = print_dependencies<arm64>;
588 break;
589 case modeLinkEdit:
590 callback = process_linkedit<arm64>;
591 break;
592 case modeSize:
593 callback = collect_size<arm64>;
594 break;
2fd3f4e8
A
595 case modeNone:
596 case modeInfo:
597 case modeSlideInfo:
598 break;
599 }
600 }
601 else {
412ebb8e
A
602 fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
603 exit(1);
604 }
19894a12 605
2fd3f4e8
A
606 __block Results results;
607 results.dependentTargetFound = false;
19894a12 608 int iterateResult = dyld_shared_cache_iterate(options.mappedCache, (uint32_t)statbuf.st_size,
2fd3f4e8
A
609 ^(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo ) {
610 (callback)(dylibInfo, segInfo, options, results);
412ebb8e 611 });
2fd3f4e8
A
612 if ( iterateResult != 0 ) {
613 fprintf(stderr, "Error: malformed shared cache file\n");
614 exit(1);
615 }
412ebb8e 616
2fd3f4e8 617 if ( options.mode == modeLinkEdit ) {
412ebb8e 618 // dump -linkedit information
2fd3f4e8
A
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);
412ebb8e
A
621 }
622 }
19894a12
A
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);
627 }
628 }
412ebb8e 629
2fd3f4e8
A
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);
412ebb8e
A
632 exit(1);
633 }
634 }
635 return 0;
636}