]> git.saurik.com Git - apple/dyld.git/blob - launch-cache/dyld_shared_cache_util.cpp
dyld-551.4.tar.gz
[apple/dyld.git] / launch-cache / dyld_shared_cache_util.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
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 <dlfcn.h>
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <sys/mman.h>
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/mach.h>
39
40 #include <map>
41 #include <vector>
42
43 #include "dsc_iterator.h"
44 #include "dsc_extractor.h"
45 #include "dyld_cache_format.h"
46 #include "Architectures.hpp"
47 #include "MachOFileAbstraction.hpp"
48 #include "CacheFileAbstraction.hpp"
49 #include "Trie.hpp"
50
51 enum Mode {
52 modeNone,
53 modeList,
54 modeMap,
55 modeDependencies,
56 modeSlideInfo,
57 modeAcceleratorInfo,
58 modeTextInfo,
59 modeLinkEdit,
60 modeLocalSymbols,
61 modeInfo,
62 modeSize,
63 modeExtract
64 };
65
66 struct Options {
67 Mode mode;
68 const char* dependentsOfPath;
69 const void* mappedCache;
70 const char* extractionDir;
71 bool printUUIDs;
72 bool printVMAddrs;
73 bool printDylibVersions;
74 bool printInodes;
75 };
76
77 struct TextInfo {
78 uint64_t textSize;
79 const char* path;
80 };
81
82 struct TextInfoSorter {
83 bool operator()(const TextInfo& left, const TextInfo& right) {
84 return (left.textSize > right.textSize);
85 }
86 };
87
88 struct Results {
89 std::map<uint32_t, const char*> pageToContent;
90 uint64_t linkeditBase;
91 bool dependentTargetFound;
92 std::vector<TextInfo> textSegments;
93 };
94
95
96
97 void usage() {
98 fprintf(stderr, "Usage: dyld_shared_cache_util -list [ -uuid ] [-vmaddr] | -dependents <dylib-path> [ -versions ] | -linkedit | -map | -slide_info | -info | -extract <dylib-dir> [ shared-cache-file ] \n");
99 }
100
101 #if __x86_64__
102 static bool isHaswell()
103 {
104 // check system is capable of running x86_64h code
105 struct host_basic_info info;
106 mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
107 mach_port_t hostPort = mach_host_self();
108 kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
109 mach_port_deallocate(mach_task_self(), hostPort);
110 if ( result != KERN_SUCCESS )
111 return false;
112 return ( info.cpu_subtype == CPU_SUBTYPE_X86_64_H );
113 }
114 #endif
115
116 /*
117 * Get the path to the native shared cache for this host
118 */
119 static const char* default_shared_cache_path() {
120 #if __i386__
121 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "i386";
122 #elif __x86_64__
123 if ( isHaswell() )
124 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "x86_64h";
125 else
126 return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "x86_64";
127 #elif __ARM_ARCH_5TEJ__
128 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv5";
129 #elif __ARM_ARCH_6K__
130 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv6";
131 #elif __ARM_ARCH_7K__
132 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7k";
133 #elif __ARM_ARCH_7A__
134 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7";
135 #elif __ARM_ARCH_7F__
136 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7f";
137 #elif __ARM_ARCH_7S__
138 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7s";
139 #elif __arm64e__
140 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "arm64e";
141 #elif __arm64__
142 return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "arm64";
143 #else
144 #error unsupported architecture
145 #endif
146 }
147
148 typedef void (*segment_callback_t)(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
149 const Options& options, Results& results);
150
151
152
153 /*
154 * List dependencies from the mach-o header at headerAddr
155 * in the same format as 'otool -L'
156 */
157 template <typename A>
158 void print_dependencies(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
159 const Options& options, Results& results) {
160 typedef typename A::P P;
161 typedef typename A::P::E E;
162
163 if ( strcmp(options.dependentsOfPath, dylibInfo->path) != 0 )
164 return;
165 if ( strcmp(segInfo->name, "__TEXT") != 0 )
166 return;
167
168 const macho_dylib_command<P>* dylib_cmd;
169 const macho_header<P>* mh = (const macho_header<P>*)dylibInfo->machHeader;
170 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uintptr_t)dylibInfo->machHeader + sizeof(macho_header<P>));
171 const uint32_t cmd_count = mh->ncmds();
172 const macho_load_command<P>* cmd = cmds;
173 for (uint32_t i = 0; i < cmd_count; ++i) {
174 switch ( cmd->cmd() ) {
175 case LC_LOAD_DYLIB:
176 case LC_ID_DYLIB:
177 case LC_REEXPORT_DYLIB:
178 case LC_LOAD_WEAK_DYLIB:
179 case LC_LOAD_UPWARD_DYLIB:
180 dylib_cmd = (macho_dylib_command<P>*)cmd;
181 if ( options.printDylibVersions ) {
182 uint32_t compat_vers = dylib_cmd->compatibility_version();
183 uint32_t current_vers = dylib_cmd->current_version();
184 printf("\t%s", dylib_cmd->name());
185 if ( compat_vers != 0xFFFFFFFF ) {
186 printf("(compatibility version %u.%u.%u, current version %u.%u.%u)\n",
187 (compat_vers >> 16),
188 (compat_vers >> 8) & 0xff,
189 (compat_vers) & 0xff,
190 (current_vers >> 16),
191 (current_vers >> 8) & 0xff,
192 (current_vers) & 0xff);
193 }
194 else {
195 printf("\n");
196 }
197 }
198 else {
199 printf("\t%s\n", dylib_cmd->name());
200 }
201 break;
202 }
203 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
204 }
205 results.dependentTargetFound = true;
206 }
207
208 /*
209 * Print out a dylib from the shared cache, optionally including the UUID or unslid load address
210 */
211 template <typename A>
212 void print_list(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
213 const Options& options, Results& results)
214 {
215 if ( strcmp(segInfo->name, "__TEXT") != 0 )
216 return;
217
218 if ( options.printVMAddrs )
219 printf("0x%08llX ", segInfo->address);
220 if ( options.printInodes )
221 printf("0x%08llX 0x%08llX ", dylibInfo->inode, dylibInfo->modTime);
222 if ( options.printUUIDs ) {
223 if ( dylibInfo->uuid != NULL ) {
224 const uint8_t* uuid = (uint8_t*)dylibInfo->uuid;;
225 printf("<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X> ",
226 uuid[0], uuid[1], uuid[2], uuid[3],
227 uuid[4], uuid[5], uuid[6], uuid[7],
228 uuid[8], uuid[9], uuid[10], uuid[11],
229 uuid[12], uuid[13], uuid[14], uuid[15]);
230 }
231 else
232 printf("< no uuid in dylib > ");
233 }
234 if ( dylibInfo->isAlias )
235 printf("[alias] %s\n", dylibInfo->path);
236 else
237 printf("%s\n", dylibInfo->path);
238 }
239
240
241 template <typename A>
242 void collect_size(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
243 const Options& options, Results& results)
244 {
245 if ( strcmp(segInfo->name, "__TEXT") != 0 )
246 return;
247 if ( dylibInfo->isAlias )
248 return;
249
250 TextInfo info;
251 info.textSize = segInfo->fileSize;
252 info.path = dylibInfo->path;
253 results.textSegments.push_back(info);
254 }
255
256
257
258
259 static void add_linkedit(uint32_t pageStart, uint32_t pageEnd, const char* message, Results& results)
260 {
261 for (uint32_t p = pageStart; p <= pageEnd; p += 4096) {
262 std::map<uint32_t, const char*>::iterator pos = results.pageToContent.find(p);
263 if ( pos == results.pageToContent.end() ) {
264 results.pageToContent[p] = strdup(message);
265 }
266 else {
267 const char* oldMessage = pos->second;
268 char* newMesssage;
269 asprintf(&newMesssage, "%s, %s", oldMessage, message);
270 results.pageToContent[p] = newMesssage;
271 ::free((void*)oldMessage);
272 }
273 }
274 }
275
276
277 /*
278 * get LINKEDIT info for dylib
279 */
280 template <typename A>
281 void process_linkedit(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
282 const Options& options, Results& results) {
283 typedef typename A::P P;
284 typedef typename A::P::E E;
285 // filter out symlinks
286 if ( dylibInfo->isAlias )
287 return;
288 const macho_header<P>* mh = (const macho_header<P>*)dylibInfo->machHeader;
289 uint32_t ncmds = mh->ncmds();
290 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((long)mh + sizeof(macho_header<P>));
291 const macho_load_command<P>* cmd = cmds;
292 for (uint32_t i = 0; i < ncmds; i++) {
293 if ( cmd->cmd() == LC_DYLD_INFO_ONLY ) {
294 macho_dyld_info_command<P>* dyldInfo = (macho_dyld_info_command<P>*)cmd;
295 char message[1000];
296 const char* shortName = strrchr(dylibInfo->path, '/') + 1;
297 // add export trie info
298 if ( dyldInfo->export_size() != 0 ) {
299 //printf("export_off=0x%X\n", dyldInfo->export_off());
300 uint32_t exportPageOffsetStart = dyldInfo->export_off() & (-4096);
301 uint32_t exportPageOffsetEnd = (dyldInfo->export_off() + dyldInfo->export_size()) & (-4096);
302 sprintf(message, "exports from %s", shortName);
303 add_linkedit(exportPageOffsetStart, exportPageOffsetEnd, message, results);
304 }
305 // add binding info
306 if ( dyldInfo->bind_size() != 0 ) {
307 uint32_t bindPageOffsetStart = dyldInfo->bind_off() & (-4096);
308 uint32_t bindPageOffsetEnd = (dyldInfo->bind_off() + dyldInfo->bind_size()) & (-4096);
309 sprintf(message, "bindings from %s", shortName);
310 add_linkedit(bindPageOffsetStart, bindPageOffsetEnd, message, results);
311 }
312 // add lazy binding info
313 if ( dyldInfo->lazy_bind_size() != 0 ) {
314 uint32_t lazybindPageOffsetStart = dyldInfo->lazy_bind_off() & (-4096);
315 uint32_t lazybindPageOffsetEnd = (dyldInfo->lazy_bind_off() + dyldInfo->lazy_bind_size()) & (-4096);
316 sprintf(message, "lazy bindings from %s", shortName);
317 add_linkedit(lazybindPageOffsetStart, lazybindPageOffsetEnd, message, results);
318 }
319 // add weak binding info
320 if ( dyldInfo->weak_bind_size() != 0 ) {
321 uint32_t weakbindPageOffsetStart = dyldInfo->weak_bind_off() & (-4096);
322 uint32_t weakbindPageOffsetEnd = (dyldInfo->weak_bind_off() + dyldInfo->weak_bind_size()) & (-4096);
323 sprintf(message, "weak bindings from %s", shortName);
324 add_linkedit(weakbindPageOffsetStart, weakbindPageOffsetEnd, message, results);
325 }
326 }
327 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
328 }
329 }
330
331
332 /*
333 * Print out a .map file similar to what update_dyld_shared_cache created when the cache file was built
334 */
335 template <typename A>
336 void print_map(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo, const Options& options, Results& results) {
337 if ( !dylibInfo->isAlias )
338 printf("0x%08llX - 0x%08llX %s %s\n", segInfo->address, segInfo->address + segInfo->fileSize, segInfo->name, dylibInfo->path);
339 }
340
341
342 static void checkMode(Mode mode) {
343 if ( mode != modeNone ) {
344 fprintf(stderr, "Error: select one of: -list, -dependents, -info, -slide_info, -linkedit, -map, -extract, or -size\n");
345 usage();
346 exit(1);
347 }
348 }
349
350 int main (int argc, const char* argv[]) {
351
352 const char* sharedCachePath = default_shared_cache_path();
353
354 Options options;
355 options.mode = modeNone;
356 options.printUUIDs = false;
357 options.printVMAddrs = false;
358 options.printDylibVersions = false;
359 options.printInodes = false;
360 options.dependentsOfPath = NULL;
361 options.extractionDir = NULL;
362
363 for (uint32_t i = 1; i < argc; i++) {
364 const char* opt = argv[i];
365 if (opt[0] == '-') {
366 if (strcmp(opt, "-list") == 0) {
367 checkMode(options.mode);
368 options.mode = modeList;
369 }
370 else if (strcmp(opt, "-dependents") == 0) {
371 checkMode(options.mode);
372 options.mode = modeDependencies;
373 options.dependentsOfPath = argv[++i];
374 if ( i >= argc ) {
375 fprintf(stderr, "Error: option -depdendents requires an argument\n");
376 usage();
377 exit(1);
378 }
379 }
380 else if (strcmp(opt, "-linkedit") == 0) {
381 checkMode(options.mode);
382 options.mode = modeLinkEdit;
383 }
384 else if (strcmp(opt, "-info") == 0) {
385 checkMode(options.mode);
386 options.mode = modeInfo;
387 }
388 else if (strcmp(opt, "-slide_info") == 0) {
389 checkMode(options.mode);
390 options.mode = modeSlideInfo;
391 }
392 else if (strcmp(opt, "-accelerator_info") == 0) {
393 checkMode(options.mode);
394 options.mode = modeAcceleratorInfo;
395 }
396 else if (strcmp(opt, "-text_info") == 0) {
397 checkMode(options.mode);
398 options.mode = modeTextInfo;
399 }
400 else if (strcmp(opt, "-local_symbols") == 0) {
401 checkMode(options.mode);
402 options.mode = modeLocalSymbols;
403 }
404 else if (strcmp(opt, "-map") == 0) {
405 checkMode(options.mode);
406 options.mode = modeMap;
407 }
408 else if (strcmp(opt, "-size") == 0) {
409 checkMode(options.mode);
410 options.mode = modeSize;
411 }
412 else if (strcmp(opt, "-extract") == 0) {
413 checkMode(options.mode);
414 options.mode = modeExtract;
415 options.extractionDir = argv[++i];
416 if ( i >= argc ) {
417 fprintf(stderr, "Error: option -extract requires a directory argument\n");
418 usage();
419 exit(1);
420 }
421 }
422 else if (strcmp(opt, "-uuid") == 0) {
423 options.printUUIDs = true;
424 }
425 else if (strcmp(opt, "-inode") == 0) {
426 options.printInodes = true;
427 }
428 else if (strcmp(opt, "-versions") == 0) {
429 options.printDylibVersions = true;
430 }
431 else if (strcmp(opt, "-vmaddr") == 0) {
432 options.printVMAddrs = true;
433 }
434 else {
435 fprintf(stderr, "Error: unrecognized option %s\n", opt);
436 usage();
437 exit(1);
438 }
439 }
440 else {
441 sharedCachePath = opt;
442 }
443 }
444
445 if ( options.mode == modeNone ) {
446 fprintf(stderr, "Error: select one of -list, -dependents, -info, -linkedit, or -map\n");
447 usage();
448 exit(1);
449 }
450
451 if ( options.mode != modeSlideInfo ) {
452 if ( options.printUUIDs && (options.mode != modeList) )
453 fprintf(stderr, "Warning: -uuid option ignored outside of -list mode\n");
454
455 if ( options.printVMAddrs && (options.mode != modeList) )
456 fprintf(stderr, "Warning: -vmaddr option ignored outside of -list mode\n");
457
458 if ( options.printDylibVersions && (options.mode != modeDependencies) )
459 fprintf(stderr, "Warning: -versions option ignored outside of -dependents mode\n");
460
461 if ( (options.mode == modeDependencies) && (options.dependentsOfPath == NULL) ) {
462 fprintf(stderr, "Error: -dependents given, but no dylib path specified\n");
463 usage();
464 exit(1);
465 }
466 }
467
468 struct stat statbuf;
469 if ( ::stat(sharedCachePath, &statbuf) == -1 ) {
470 fprintf(stderr, "Error: stat() failed for dyld shared cache at %s, errno=%d\n", sharedCachePath, errno);
471 exit(1);
472 }
473
474 int cache_fd = ::open(sharedCachePath, O_RDONLY);
475 if ( cache_fd < 0 ) {
476 fprintf(stderr, "Error: open() failed for shared cache file at %s, errno=%d\n", sharedCachePath, errno);
477 exit(1);
478 }
479 options.mappedCache = ::mmap(NULL, (size_t)statbuf.st_size, PROT_READ, MAP_PRIVATE, cache_fd, 0);
480 if (options.mappedCache == MAP_FAILED) {
481 fprintf(stderr, "Error: mmap() for shared cache at %s failed, errno=%d\n", sharedCachePath, errno);
482 exit(1);
483 }
484
485 if ( options.mode == modeSlideInfo ) {
486 const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)options.mappedCache;
487 if ( header->slideInfoOffset() == 0 ) {
488 fprintf(stderr, "Error: dyld shared cache does not contain slide info\n");
489 exit(1);
490 }
491 const dyldCacheFileMapping<LittleEndian>* mappings = (dyldCacheFileMapping<LittleEndian>*)((char*)options.mappedCache + header->mappingOffset());
492 const dyldCacheFileMapping<LittleEndian>* dataMapping = &mappings[1];
493 uint64_t dataStartAddress = dataMapping->address();
494 uint64_t dataSize = dataMapping->size();
495 const dyldCacheSlideInfo<LittleEndian>* slideInfoHeader = (dyldCacheSlideInfo<LittleEndian>*)((char*)options.mappedCache+header->slideInfoOffset());
496 printf("slide info version=%d\n", slideInfoHeader->version());
497 if ( slideInfoHeader->version() == 1 ) {
498 printf("toc_count=%d, data page count=%lld\n", slideInfoHeader->toc_count(), dataSize/4096);
499 const dyldCacheSlideInfoEntry* entries = (dyldCacheSlideInfoEntry*)((char*)slideInfoHeader + slideInfoHeader->entries_offset());
500 for(int i=0; i < slideInfoHeader->toc_count(); ++i) {
501 printf("0x%08llX: [% 5d,% 5d] ", dataStartAddress + i*4096, i, slideInfoHeader->toc(i));
502 const dyldCacheSlideInfoEntry* entry = &entries[slideInfoHeader->toc(i)];
503 for(int j=0; j < slideInfoHeader->entries_size(); ++j)
504 printf("%02X", entry->bits[j]);
505 printf("\n");
506 }
507 }
508 else if ( slideInfoHeader->version() == 2 ) {
509 const dyldCacheSlideInfo2<LittleEndian>* slideInfo = (dyldCacheSlideInfo2<LittleEndian>*)(slideInfoHeader);
510 printf("page_size=%d\n", slideInfo->page_size());
511 printf("delta_mask=0x%016llX\n", slideInfo->delta_mask());
512 printf("value_add=0x%016llX\n", slideInfo->value_add());
513 printf("page_starts_count=%d, page_extras_count=%d\n", slideInfo->page_starts_count(), slideInfo->page_extras_count());
514 const uint16_t* starts = (uint16_t* )((char*)slideInfo + slideInfo->page_starts_offset());
515 const uint16_t* extras = (uint16_t* )((char*)slideInfo + slideInfo->page_extras_offset());
516 for (int i=0; i < slideInfo->page_starts_count(); ++i) {
517 const uint16_t start = starts[i];
518 if ( start == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE ) {
519 printf("page[% 5d]: no rebasing\n", i);
520 }
521 else if ( start & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA ) {
522 printf("page[% 5d]: ", i);
523 int j=(start & 0x3FFF);
524 bool done = false;
525 do {
526 uint16_t aStart = extras[j];
527 printf("start=0x%04X ", aStart & 0x3FFF);
528 done = (extras[j] & DYLD_CACHE_SLIDE_PAGE_ATTR_END);
529 ++j;
530 } while ( !done );
531 printf("\n");
532 }
533 else {
534 printf("page[% 5d]: start=0x%04X\n", i, starts[i]);
535 }
536 }
537 }
538 }
539 else if ( options.mode == modeInfo ) {
540 const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)options.mappedCache;
541 printf("uuid: ");
542 if ( header->mappingOffset() >= 0x68 ) {
543 const uint8_t* uuid = header->uuid();
544 printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
545 uuid[0], uuid[1], uuid[2], uuid[3],
546 uuid[4], uuid[5], uuid[6], uuid[7],
547 uuid[8], uuid[9], uuid[10], uuid[11],
548 uuid[12], uuid[13], uuid[14], uuid[15]);
549 }
550 else {
551 printf("n/a\n");
552 }
553 if ( header->mappingOffset() >= 0xE0 ) {
554 // HACK until this uses new header
555 uint32_t platform = *((uint32_t*)(((char*)header) + 0xD8));
556 uint32_t simulator = *((uint32_t*)(((char*)header) + 0xDC));
557 switch (platform) {
558 case 1:
559 printf("platform: macOS\n");
560 break;
561 case 2:
562 if ( simulator & 0x400 )
563 printf("platform: iOS simulator\n");
564 else
565 printf("platform: iOS\n");
566 break;
567 case 3:
568 if ( simulator & 0x400 )
569 printf("platform: tvOS simulator\n");
570 else
571 printf("platform: tvOS\n");
572 break;
573 case 4:
574 if ( simulator & 0x400 )
575 printf("platform: watchOS simulator\n");
576 else
577 printf("platform: watchOS\n");
578 break;
579 case 5:
580 printf("platform: bridgeOS\n");
581 break;
582 default:
583 printf("platform: 0x%08X 0x%08X\n", platform, simulator);
584 }
585 }
586 printf("image count: %u\n", header->imagesCount());
587 if ( (header->mappingOffset() >= 0x78) && (header->branchPoolsOffset() != 0) ) {
588 printf("branch pool count: %u\n", header->branchPoolsCount());
589 }
590 printf("mappings:\n");
591 const dyldCacheFileMapping<LittleEndian>* mappings = (dyldCacheFileMapping<LittleEndian>*)((char*)options.mappedCache + header->mappingOffset());
592 for (uint32_t i=0; i < header->mappingCount(); ++i) {
593 if ( mappings[i].init_prot() & VM_PROT_EXECUTE )
594 printf(" __TEXT %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
595 mappings[i].size()/(1024*1024), mappings[i].file_offset(), mappings[i].file_offset() + mappings[i].size(),
596 mappings[i].address(), mappings[i].address() + mappings[i].size());
597 else if ( mappings[i]. init_prot() & VM_PROT_WRITE )
598 printf(" __DATA %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
599 mappings[i].size()/(1024*1024), mappings[i].file_offset(), mappings[i].file_offset() + mappings[i].size(),
600 mappings[i].address(), mappings[i].address() + mappings[i].size());
601 else if ( mappings[i].init_prot() & VM_PROT_READ )
602 printf(" __LINKEDIT %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
603 mappings[i].size()/(1024*1024), mappings[i].file_offset(), mappings[i].file_offset() + mappings[i].size(),
604 mappings[i].address(), mappings[i].address() + mappings[i].size());
605 }
606 if ( header->codeSignatureOffset() != 0 ) {
607 uint64_t size = statbuf.st_size - header->codeSignatureOffset();
608 uint64_t csAddr = mappings[header->mappingCount()-1].address() + mappings[header->mappingCount()-1].size();
609 if ( size != 0 )
610 printf(" code sign %3lluMB, file offset: 0x%08llX -> 0x%08llX, address: 0x%08llX -> 0x%08llX\n",
611 size/(1024*1024), header->codeSignatureOffset(), header->codeSignatureOffset() + size, csAddr, csAddr + size);
612 }
613 printf("slide info: %4lluKB, file offset: 0x%08llX -> 0x%08llX\n",
614 header->slideInfoSize()/1024, header->slideInfoOffset(), header->slideInfoOffset() + header->slideInfoSize());
615 if ( header->localSymbolsOffset() != 0 )
616 printf("local symbols: %3lluMB, file offset: 0x%08llX -> 0x%08llX\n",
617 header->localSymbolsSize()/(1024*1024), header->localSymbolsOffset(), header->localSymbolsOffset() + header->localSymbolsSize());
618 if ( (header->mappingOffset() >= 0x78) && (header->accelerateInfoSize() != 0) )
619 printf("accelerate tab: %3lluKB, address: 0x%08llX -> 0x%08llX\n",
620 header->accelerateInfoSize()/1024, header->accelerateInfoAddr(), header->accelerateInfoAddr() + header->accelerateInfoSize());
621 }
622 else if ( options.mode == modeAcceleratorInfo ) {
623 const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)options.mappedCache;
624 if ( (header->mappingOffset() < sizeof(dyldCacheHeader<LittleEndian>)) || (header->accelerateInfoSize() == 0) ) {
625 printf("no accelerator info\n");
626 }
627 else {
628 const dyldCacheFileMapping<LittleEndian>* mappings = (dyldCacheFileMapping<LittleEndian>*)((char*)options.mappedCache + header->mappingOffset());
629 uint64_t aiAddr = header->accelerateInfoAddr();
630 dyldCacheAcceleratorInfo<LittleEndian>* accelInfo = NULL;
631 for (uint32_t i=0; i < header->mappingCount(); ++i) {
632 if ( (mappings[i].address() <= aiAddr) && (aiAddr < mappings[i].address()+mappings[i].size()) ) {
633 uint64_t offset = aiAddr - mappings[i].address() + mappings[i].file_offset();
634 accelInfo = (dyldCacheAcceleratorInfo<LittleEndian>*)((uint8_t*)options.mappedCache + offset);
635 }
636 }
637 if ( accelInfo == NULL ) {
638 printf("accelerator info not in any mapped range\n");
639 }
640 else {
641 const dyldCacheImageInfo<LittleEndian>* images = (dyldCacheImageInfo<LittleEndian>*)((char*)options.mappedCache + header->imagesOffset());
642 const dyldCacheImageInfoExtra<LittleEndian>* imagesExtra = (dyldCacheImageInfoExtra<LittleEndian>*)((char*)accelInfo + accelInfo->imagesExtrasOffset());
643 const uint16_t* dependencyArray = (uint16_t*)((char*)accelInfo + accelInfo->depListOffset());
644 const uint16_t* reExportArray = (uint16_t*)((char*)accelInfo + accelInfo->reExportListOffset());
645 printf("extra image info (count=%u):\n", accelInfo->imageExtrasCount());
646 for (uint32_t i=0; i < accelInfo->imageExtrasCount(); ++i) {
647 printf(" image[%3u] %s:\n", i, (char*)options.mappedCache +images[i].pathFileOffset());
648 printf(" exports trie: addr=0x%llX, size=0x%08X\n", imagesExtra[i].exportsTrieAddr(), imagesExtra[i].exportsTrieSize());
649 if ( imagesExtra[i].weakBindingsSize() )
650 printf(" weak bind info: addr=0x%llX, size=0x%08X\n", imagesExtra[i].weakBindingsAddr(), imagesExtra[i].weakBindingsSize());
651 printf(" dependents: ");
652 for (uint32_t d=imagesExtra[i].dependentsStartArrayIndex(); dependencyArray[d] != 0xFFFF; ++d) {
653 uint16_t depIndex = dependencyArray[d];
654 if ( depIndex & 0x8000 )
655 printf(" up(%d) ", depIndex & 0x7FFF);
656 else
657 printf(" %d ", depIndex);
658 }
659 printf("\n");
660 printf(" re-exports: ");
661 for (uint32_t r=imagesExtra[i].reExportsStartArrayIndex(); reExportArray[r] != 0xFFFF; ++r)
662 printf(" %d ", reExportArray[r]);
663 printf("\n");
664 }
665 printf("libdyld.dylib:\n");
666 printf(" __dyld section address: 0x%llX\n", accelInfo->dyldSectionAddr());
667 printf("initializers (count=%u):\n", accelInfo->initializersCount());
668 const dyldCacheAcceleratorInitializer<LittleEndian>* initializers = (dyldCacheAcceleratorInitializer<LittleEndian>*)((char*)accelInfo + accelInfo->initializersOffset());
669 for (uint32_t i=0; i < accelInfo->initializersCount(); ++i) {
670 printf(" image[%3u] 0x%llX\n", initializers[i].imageIndex(), mappings[0].address() + initializers[i].functionOffset());
671 }
672 printf("DOF sections (count=%u):\n", accelInfo->dofSectionsCount());
673 const dyldCacheAcceleratorDOFEntry<LittleEndian>* dofs = (dyldCacheAcceleratorDOFEntry<LittleEndian>*)((char*)accelInfo + accelInfo->dofSectionsOffset());
674 for (uint32_t i=0; i < accelInfo->dofSectionsCount(); ++i) {
675 printf(" image[%3u] 0x%llX -> 0x%llX\n", dofs[i].imageIndex(), dofs[i].sectionAddress(), dofs[i].sectionAddress()+dofs[i].sectionSize());
676 }
677 printf("bottom up order (count=%u):\n", accelInfo->imageExtrasCount());
678 const uint16_t* bottomUpArray = (uint16_t*)((char*)accelInfo + accelInfo->bottomUpListOffset());
679 for (uint32_t i=0; i < accelInfo->imageExtrasCount(); ++i) {
680 unsigned imageIndex = bottomUpArray[i];
681 if ( imageIndex < accelInfo->imageExtrasCount() )
682 printf(" image[%3u] %s\n", imageIndex, (char*)options.mappedCache + images[imageIndex].pathFileOffset());
683 else
684 printf(" image[%3u] BAD INDEX\n", imageIndex);
685 }
686 printf("range table (count=%u):\n", accelInfo->rangeTableCount());
687 const dyldCacheAcceleratorRangeEntry<LittleEndian>* rangeTable = (dyldCacheAcceleratorRangeEntry<LittleEndian>*)((char*)accelInfo + accelInfo->rangeTableOffset());
688 for (uint32_t i=0; i < accelInfo->rangeTableCount(); ++i) {
689 const dyldCacheAcceleratorRangeEntry<LittleEndian>& entry = rangeTable[i];
690 printf(" 0x%llX -> 0x%llX %s\n", entry.startAddress(), entry.startAddress() + entry.size(), (char*)options.mappedCache + images[entry.imageIndex()].pathFileOffset());
691 }
692 printf("dylib trie (size=%u):\n", accelInfo->dylibTrieSize());
693 const uint8_t* dylibTrieStart = (uint8_t*)accelInfo + accelInfo->dylibTrieOffset();
694 const uint8_t* dylibTrieEnd = dylibTrieStart + accelInfo->dylibTrieSize();
695 std::vector<DylibIndexTrie::Entry> dylibEntries;
696 if ( !Trie<DylibIndex>::parseTrie(dylibTrieStart, dylibTrieEnd, dylibEntries) )
697 printf(" malformed dylibs trie\n");
698 for (const DylibIndexTrie::Entry& x : dylibEntries) {
699 printf(" image[%3u] %s\n", x.info.index, x.name.c_str());
700 }
701 }
702 }
703 }
704 else if ( options.mode == modeTextInfo ) {
705 const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)options.mappedCache;
706 if ( (header->mappingOffset() < sizeof(dyldCacheHeader<LittleEndian>)) || (header->imagesTextCount() == 0) ) {
707 printf("no text info\n");
708 }
709 else {
710 const dyldCacheImageTextInfo<LittleEndian>* imagesText = (dyldCacheImageTextInfo<LittleEndian>*)((char*)options.mappedCache + header->imagesTextOffset());
711 const dyldCacheImageTextInfo<LittleEndian>* imagesTextEnd = &imagesText[header->imagesTextCount()];
712 printf("dylib text infos (count=%llu):\n", header->imagesTextCount());
713 for (const dyldCacheImageTextInfo<LittleEndian>* p=imagesText; p < imagesTextEnd; ++p) {
714 printf(" 0x%09llX -> 0x%09llX <", p->loadAddress(), p->loadAddress() + p->textSegmentSize());
715 for (int i=0; i<16; ++i) {
716 switch (i) {
717 case 4:
718 case 6:
719 case 8:
720 case 10:
721 printf("-");
722 break;
723 }
724 printf("%02X", p->uuid()[i]);
725 }
726 printf("> %s\n", (char*)options.mappedCache + p->pathOffset());
727 }
728 }
729 }
730 else if ( options.mode == modeLocalSymbols ) {
731 const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)options.mappedCache;
732 if ( header->localSymbolsOffset() == 0 ) {
733 fprintf(stderr, "Error: dyld shared cache does not contain local symbols info\n");
734 exit(1);
735 }
736 const bool is64 = (strstr((char*)options.mappedCache, "64") != NULL);
737 const dyldCacheImageInfo<LittleEndian>* imageInfos = (dyldCacheImageInfo<LittleEndian>*)((char*)options.mappedCache + header->imagesOffset());
738 const dyldCacheLocalSymbolsInfo<LittleEndian>* localsInfo = (dyldCacheLocalSymbolsInfo<LittleEndian>*)((char*)options.mappedCache + header->localSymbolsOffset());
739 const uint32_t nlistFileOffset = (uint32_t)(header->localSymbolsOffset() + localsInfo->nlistOffset());
740 const uint32_t nlistCount = localsInfo->nlistCount();
741 const uint32_t nlistByteSize = is64 ? nlistCount*16 : nlistCount*12;
742 const uint32_t stringsFileOffset = (uint32_t)(header->localSymbolsOffset() + localsInfo->stringsOffset());
743 const uint32_t stringsSize = localsInfo->stringsSize();
744 const uint32_t entriesCount = localsInfo->entriesCount();
745 const dyldCacheLocalSymbolEntry<LittleEndian>* entries = (dyldCacheLocalSymbolEntry<LittleEndian>*)((char*)localsInfo + localsInfo->entriesOffset());
746 printf("local symbols nlist array: %3uMB, file offset: 0x%08X -> 0x%08X\n", nlistByteSize/(1024*1024), nlistFileOffset, nlistFileOffset+nlistByteSize);
747 printf("local symbols string pool: %3uMB, file offset: 0x%08X -> 0x%08X\n", stringsSize/(1024*1024), stringsFileOffset, stringsFileOffset+stringsSize);
748 printf("local symbols by dylib (count=%d):\n", entriesCount);
749 //const char* stringPool = (char*)options.mappedCache + stringsFileOffset;
750 for (int i=0; i < entriesCount; ++i) {
751 const char* imageName = (char*)options.mappedCache + imageInfos[i].pathFileOffset();
752 printf(" nlistStartIndex=%5d, nlistCount=%5d, image=%s\n", entries[i].nlistStartIndex(), entries[i].nlistCount(), imageName);
753 #if 0
754 if ( is64 ) {
755 const nlist_64* symTab = (nlist_64*)((char*)options.mappedCache + nlistFileOffset);
756 for (int e=0; e < entries[i].nlistCount(); ++e) {
757 const nlist_64* entry = &symTab[entries[i].nlistStartIndex()+e];
758 printf(" nlist[%d].str=%d, %s\n", e, entry->n_un.n_strx, &stringPool[entry->n_un.n_strx]);
759 printf(" nlist[%d].value=0x%0llX\n", e, entry->n_value);
760 }
761 }
762 #endif
763 }
764 }
765 else if ( options.mode == modeExtract ) {
766 char pathBuffer[PATH_MAX];
767 uint32_t bufferSize = PATH_MAX;
768 if ( _NSGetExecutablePath(pathBuffer, &bufferSize) != 0 ) {
769 fprintf(stderr, "Error: could not get path of program\n");
770 return 1;
771 }
772 char* last = strrchr(pathBuffer, '/');
773 strcpy(last+1, "../../lib/dsc_extractor.bundle");
774 void* handle = dlopen(pathBuffer, RTLD_LAZY);
775 if ( handle == NULL ) {
776 fprintf(stderr, "Error: dsc_extractor.bundle could not be loaded at %s\n", pathBuffer);
777 return 1;
778 }
779
780 typedef int (*extractor_proc)(const char* shared_cache_file_path, const char* extraction_root_path,
781 void (^progress)(unsigned current, unsigned total));
782
783 extractor_proc proc = (extractor_proc)dlsym(handle, "dyld_shared_cache_extract_dylibs_progress");
784 if ( proc == NULL ) {
785 fprintf(stderr, "Error: dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
786 return 1;
787 }
788
789 int result = (*proc)(sharedCachePath, options.extractionDir, ^(unsigned c, unsigned total) { } );
790 return result;
791 }
792 else {
793 segment_callback_t callback = nullptr;
794 if ( strcmp((char*)options.mappedCache, "dyld_v1 i386") == 0 ) {
795 switch ( options.mode ) {
796 case modeList:
797 callback = print_list<x86>;
798 break;
799 case modeMap:
800 callback = print_map<x86>;
801 break;
802 case modeDependencies:
803 callback = print_dependencies<x86>;
804 break;
805 case modeLinkEdit:
806 callback = process_linkedit<x86>;
807 break;
808 case modeSize:
809 callback = collect_size<x86>;
810 break;
811 case modeNone:
812 case modeInfo:
813 case modeSlideInfo:
814 case modeAcceleratorInfo:
815 case modeTextInfo:
816 case modeLocalSymbols:
817 case modeExtract:
818 break;
819 }
820 }
821 else if ( (strcmp((char*)options.mappedCache, "dyld_v1 x86_64") == 0)
822 || (strcmp((char*)options.mappedCache, "dyld_v1 x86_64h") == 0) ) {
823 switch ( options.mode ) {
824 case modeList:
825 callback = print_list<x86_64>;
826 break;
827 case modeMap:
828 callback = print_map<x86_64>;
829 break;
830 case modeDependencies:
831 callback = print_dependencies<x86_64>;
832 break;
833 case modeLinkEdit:
834 callback = process_linkedit<x86_64>;
835 break;
836 case modeSize:
837 callback = collect_size<x86_64>;
838 break;
839 case modeNone:
840 case modeInfo:
841 case modeSlideInfo:
842 case modeAcceleratorInfo:
843 case modeTextInfo:
844 case modeLocalSymbols:
845 case modeExtract:
846 break;
847 }
848 }
849 else if ( (strncmp((char*)options.mappedCache, "dyld_v1 armv", 14) == 0)
850 || (strncmp((char*)options.mappedCache, "dyld_v1 armv", 13) == 0) ) {
851 switch ( options.mode ) {
852 case modeList:
853 callback = print_list<arm>;
854 break;
855 case modeMap:
856 callback = print_map<arm>;
857 break;
858 case modeDependencies:
859 callback = print_dependencies<arm>;
860 break;
861 case modeLinkEdit:
862 callback = process_linkedit<arm>;
863 break;
864 case modeSize:
865 callback = collect_size<arm>;
866 break;
867 case modeNone:
868 case modeInfo:
869 case modeSlideInfo:
870 case modeAcceleratorInfo:
871 case modeTextInfo:
872 case modeLocalSymbols:
873 case modeExtract:
874 break;
875 }
876 }
877 else if ( (strcmp((char*)options.mappedCache, "dyld_v1 arm64") == 0)
878 || (strcmp((char*)options.mappedCache, "dyld_v1 arm64e") == 0) ) {
879 switch ( options.mode ) {
880 case modeList:
881 callback = print_list<arm64>;
882 break;
883 case modeMap:
884 callback = print_map<arm64>;
885 break;
886 case modeDependencies:
887 callback = print_dependencies<arm64>;
888 break;
889 case modeLinkEdit:
890 callback = process_linkedit<arm64>;
891 break;
892 case modeSize:
893 callback = collect_size<arm64>;
894 break;
895 case modeNone:
896 case modeInfo:
897 case modeSlideInfo:
898 case modeAcceleratorInfo:
899 case modeTextInfo:
900 case modeLocalSymbols:
901 case modeExtract:
902 break;
903 }
904 }
905 else {
906 fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
907 exit(1);
908 }
909
910 __block Results results;
911 results.dependentTargetFound = false;
912 int iterateResult = dyld_shared_cache_iterate(options.mappedCache, (uint32_t)statbuf.st_size,
913 ^(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo ) {
914 (callback)(dylibInfo, segInfo, options, results);
915 });
916 if ( iterateResult != 0 ) {
917 fprintf(stderr, "Error: malformed shared cache file\n");
918 exit(1);
919 }
920
921 if ( options.mode == modeLinkEdit ) {
922 // dump -linkedit information
923 for (std::map<uint32_t, const char*>::iterator it = results.pageToContent.begin(); it != results.pageToContent.end(); ++it) {
924 printf("0x%08X %s\n", it->first, it->second);
925 }
926 }
927 else if ( options.mode == modeSize ) {
928 std::sort(results.textSegments.begin(), results.textSegments.end(), TextInfoSorter());
929 for (std::vector<TextInfo>::iterator it = results.textSegments.begin(); it != results.textSegments.end(); ++it) {
930 printf(" 0x%08llX %s\n", it->textSize, it->path);
931 }
932 }
933
934 if ( (options.mode == modeDependencies) && options.dependentsOfPath && !results.dependentTargetFound) {
935 fprintf(stderr, "Error: could not find '%s' in the shared cache at\n %s\n", options.dependentsOfPath, sharedCachePath);
936 exit(1);
937 }
938 }
939 return 0;
940 }