]>
Commit | Line | Data |
---|---|---|
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 |
47 | enum 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 |
58 | struct 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 | ||
68 | struct TextInfo { | |
69 | uint64_t textSize; | |
70 | const char* path; | |
71 | }; | |
72 | ||
73 | struct TextInfoSorter { | |
74 | bool operator()(const TextInfo& left, const TextInfo& right) { | |
75 | return (left.textSize > right.textSize); | |
76 | } | |
2fd3f4e8 | 77 | }; |
412ebb8e | 78 | |
2fd3f4e8 A |
79 | struct 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 | 88 | void 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__ |
93 | static 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 | */ | |
110 | static 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 |
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); | |
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 | */ | |
146 | template <typename A> | |
2fd3f4e8 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) { | |
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 | */ |
200 | template <typename A> | |
2fd3f4e8 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) | |
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 |
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) | |
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 | 249 | static 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 | */ | |
270 | template <typename A> | |
2fd3f4e8 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) { | |
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 | */ |
325 | template <typename A> | |
2fd3f4e8 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); | |
412ebb8e A |
329 | } |
330 | ||
331 | ||
2fd3f4e8 A |
332 | static 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 | ||
340 | int 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 | } |