]> git.saurik.com Git - apple/dyld.git/blob - dyld3/shared-cache/dyld_closure_util.cpp
db01f5fbdd01a9e66b28989e0958ddb77086b5cb
[apple/dyld.git] / dyld3 / shared-cache / dyld_closure_util.cpp
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
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_priv.h>
38 #include <bootstrap.h>
39 #include <mach/mach.h>
40 #include <dispatch/dispatch.h>
41
42 #include <map>
43 #include <vector>
44
45 #include "LaunchCache.h"
46 #include "LaunchCacheWriter.h"
47 #include "DyldSharedCache.h"
48 #include "FileUtils.h"
49 #include "ImageProxy.h"
50 #include "StringUtils.h"
51 #include "ClosureBuffer.h"
52
53 extern "C" {
54 #include "closuredProtocol.h"
55 }
56
57 static const DyldSharedCache* mapCacheFile(const char* path)
58 {
59 struct stat statbuf;
60 if (stat(path, &statbuf)) {
61 fprintf(stderr, "Error: stat failed for dyld shared cache at %s\n", path);
62 return nullptr;
63 }
64
65 int cache_fd = open(path, O_RDONLY);
66 if (cache_fd < 0) {
67 fprintf(stderr, "Error: failed to open shared cache file at %s\n", path);
68 return nullptr;
69 }
70
71 void* mapped_cache = mmap(NULL, (size_t)statbuf.st_size, PROT_READ, MAP_PRIVATE, cache_fd, 0);
72 if (mapped_cache == MAP_FAILED) {
73 fprintf(stderr, "Error: mmap() for shared cache at %s failed, errno=%d\n", path, errno);
74 return nullptr;
75 }
76 close(cache_fd);
77
78 return (DyldSharedCache*)mapped_cache;
79 }
80
81 struct CachedSections
82 {
83 uint32_t mappedOffsetStart;
84 uint32_t mappedOffsetEnd;
85 uint64_t vmAddress;
86 const mach_header* mh;
87 std::string segmentName;
88 std::string sectionName;
89 const char* dylibPath;
90 };
91
92 static const CachedSections& find(uint32_t mappedOffset, const std::vector<CachedSections>& sections)
93 {
94 for (const CachedSections& entry : sections) {
95 //printf("0x%08X -> 0x%08X\n", entry.mappedOffsetStart, entry.mappedOffsetEnd);
96 if ( (entry.mappedOffsetStart <= mappedOffset) && (mappedOffset < entry.mappedOffsetEnd) )
97 return entry;
98 }
99 assert(0 && "invalid offset");
100 }
101
102 /*
103 static const dyld3::launch_cache::BinaryClosureData*
104 callClosureDaemon(const std::string& mainPath, const std::string& cachePath, const std::vector<std::string>& envArgs)
105 {
106
107 mach_port_t serverPort = MACH_PORT_NULL;
108 mach_port_t bootstrapPort = MACH_PORT_NULL;
109 kern_return_t kr = task_get_bootstrap_port(mach_task_self(), &bootstrapPort);
110 kr = bootstrap_look_up(bootstrapPort, "com.apple.dyld.closured", &serverPort);
111 switch( kr ) {
112 case BOOTSTRAP_SUCCESS :
113 // service currently registered, "a good thing" (tm)
114 break;
115 case BOOTSTRAP_UNKNOWN_SERVICE :
116 // service not currently registered, try again later
117 fprintf(stderr, "bootstrap_look_up(): %s\n", mach_error_string(kr));
118 return nullptr;
119 default:
120 // service not currently registered, try again later
121 fprintf(stderr, "bootstrap_look_up(): %s [%d]\n", mach_error_string(kr), kr);
122 return nullptr;
123 }
124
125 //printf("serverPort=%d, replyPort=%d\n", serverPort, replyPort);
126
127
128
129 bool success;
130 char envBuffer[2048];
131 vm_offset_t reply = 0;
132 uint32_t replySize = 0;
133 envBuffer[0] = '\0';
134 envBuffer[1] = '\0';
135 // kr = closured_CreateLaunchClosure(serverPort, mainPath.c_str(), cachePath.c_str(), uuid, envBuffer, &success, &reply, &replySize);
136
137 printf("success=%d, buf=%p, bufLen=%d\n", success, (void*)reply, replySize);
138
139 if (!success)
140 return nullptr;
141 return (const dyld3::launch_cache::BinaryClosureData*)reply;
142 }
143 */
144
145 static void usage()
146 {
147 printf("dyld_closure_util program to create of view dyld3 closures\n");
148 printf(" mode:\n");
149 printf(" -create_closure <prog-path> # create a closure for the specified main executable\n");
150 printf(" -create_image_group <dylib-path> # create an ImageGroup for the specified dylib/bundle\n");
151 printf(" -list_dyld_cache_closures # list all closures in the dyld shared cache with size\n");
152 printf(" -list_dyld_cache_other_dylibs # list all group-1 (non-cached dylibs/bundles)\n");
153 printf(" -print_image_group <closure-path> # print specified ImageGroup file as JSON\n");
154 printf(" -print_closure_file <closure-path> # print specified closure file as JSON\n");
155 printf(" -print_dyld_cache_closure <prog-path> # find closure for specified program in dyld cache and print as JSON\n");
156 printf(" -print_dyld_cache_dylibs # print group-0 (cached dylibs) as JSON\n");
157 printf(" -print_dyld_cache_other_dylibs # print group-1 (non-cached dylibs/bundles) as JSON\n");
158 printf(" -print_dyld_cache_other <path> # print just one group-1 (non-cached dylib/bundle) as JSON\n");
159 printf(" -print_dyld_cache_patch_table # print locations in shared cache that may need patching\n");
160 printf(" options:\n");
161 printf(" -cache_file <cache-path> # path to cache file to use (default is current cache)\n");
162 printf(" -build_root <path-prefix> # when building a closure, the path prefix when runtime volume is not current boot volume\n");
163 printf(" -o <output-file> # when building a closure, the file to write the (binary) closure to\n");
164 printf(" -include_all_dylibs_in_dir # when building a closure, add other mach-o files found in directory\n");
165 printf(" -env <var=value> # when building a closure, DYLD_* env vars to assume\n");
166 printf(" -dlopen <path> # for use with -create_closure to append ImageGroup if target had called dlopen\n");
167 printf(" -verbose_fixups # for use with -print* options to force printing fixups\n");
168 }
169
170 int main(int argc, const char* argv[])
171 {
172 const char* cacheFilePath = nullptr;
173 const char* inputMainExecutablePath = nullptr;
174 const char* inputTopImagePath = nullptr;
175 const char* outPath = nullptr;
176 const char* printPath = nullptr;
177 const char* printGroupPath = nullptr;
178 const char* printCacheClosure = nullptr;
179 const char* printCachedDylib = nullptr;
180 const char* printOtherDylib = nullptr;
181 bool listCacheClosures = false;
182 bool listOtherDylibs = false;
183 bool includeAllDylibs = false;
184 bool printClosures = false;
185 bool printCachedDylibs = false;
186 bool printOtherDylibs = false;
187 bool printPatchTable = false;
188 bool useClosured = false;
189 bool verboseFixups = false;
190 std::vector<std::string> buildtimePrefixes;
191 std::vector<std::string> envArgs;
192 std::vector<const char*> dlopens;
193
194 if ( argc == 1 ) {
195 usage();
196 return 0;
197 }
198
199 for (int i = 1; i < argc; ++i) {
200 const char* arg = argv[i];
201 if ( strcmp(arg, "-cache_file") == 0 ) {
202 cacheFilePath = argv[++i];
203 if ( cacheFilePath == nullptr ) {
204 fprintf(stderr, "-cache_file option requires path to cache file\n");
205 return 1;
206 }
207 }
208 else if ( strcmp(arg, "-create_closure") == 0 ) {
209 inputMainExecutablePath = argv[++i];
210 if ( inputMainExecutablePath == nullptr ) {
211 fprintf(stderr, "-create_closure option requires a path to an executable\n");
212 return 1;
213 }
214 }
215 else if ( strcmp(arg, "-create_image_group") == 0 ) {
216 inputTopImagePath = argv[++i];
217 if ( inputTopImagePath == nullptr ) {
218 fprintf(stderr, "-create_image_group option requires a path to a dylib or bundle\n");
219 return 1;
220 }
221 }
222 else if ( strcmp(arg, "-dlopen") == 0 ) {
223 const char* path = argv[++i];
224 if ( path == nullptr ) {
225 fprintf(stderr, "-dlopen option requires a path to a packed closure list\n");
226 return 1;
227 }
228 dlopens.push_back(path);
229 }
230 else if ( strcmp(arg, "-verbose_fixups") == 0 ) {
231 verboseFixups = true;
232 }
233 else if ( strcmp(arg, "-build_root") == 0 ) {
234 const char* buildRootPath = argv[++i];
235 if ( buildRootPath == nullptr ) {
236 fprintf(stderr, "-build_root option requires a path \n");
237 return 1;
238 }
239 buildtimePrefixes.push_back(buildRootPath);
240 }
241 else if ( strcmp(arg, "-o") == 0 ) {
242 outPath = argv[++i];
243 if ( outPath == nullptr ) {
244 fprintf(stderr, "-o option requires a path \n");
245 return 1;
246 }
247 }
248 else if ( strcmp(arg, "-print_closure_file") == 0 ) {
249 printPath = argv[++i];
250 if ( printPath == nullptr ) {
251 fprintf(stderr, "-print_closure_file option requires a path \n");
252 return 1;
253 }
254 }
255 else if ( strcmp(arg, "-print_image_group") == 0 ) {
256 printGroupPath = argv[++i];
257 if ( printGroupPath == nullptr ) {
258 fprintf(stderr, "-print_image_group option requires a path \n");
259 return 1;
260 }
261 }
262 else if ( strcmp(arg, "-list_dyld_cache_closures") == 0 ) {
263 listCacheClosures = true;
264 }
265 else if ( strcmp(arg, "-list_dyld_cache_other_dylibs") == 0 ) {
266 listOtherDylibs = true;
267 }
268 else if ( strcmp(arg, "-print_dyld_cache_closure") == 0 ) {
269 printCacheClosure = argv[++i];
270 if ( printCacheClosure == nullptr ) {
271 fprintf(stderr, "-print_dyld_cache_closure option requires a path \n");
272 return 1;
273 }
274 }
275 else if ( strcmp(arg, "-print_dyld_cache_closures") == 0 ) {
276 printClosures = true;
277 }
278 else if ( strcmp(arg, "-print_dyld_cache_dylibs") == 0 ) {
279 printCachedDylibs = true;
280 }
281 else if ( strcmp(arg, "-print_dyld_cache_other_dylibs") == 0 ) {
282 printOtherDylibs = true;
283 }
284 else if ( strcmp(arg, "-print_dyld_cache_dylib") == 0 ) {
285 printCachedDylib = argv[++i];
286 if ( printCachedDylib == nullptr ) {
287 fprintf(stderr, "-print_dyld_cache_dylib option requires a path \n");
288 return 1;
289 }
290 }
291 else if ( strcmp(arg, "-print_dyld_cache_other") == 0 ) {
292 printOtherDylib = argv[++i];
293 if ( printOtherDylib == nullptr ) {
294 fprintf(stderr, "-print_dyld_cache_other option requires a path \n");
295 return 1;
296 }
297 }
298 else if ( strcmp(arg, "-print_dyld_cache_patch_table") == 0 ) {
299 printPatchTable = true;
300 }
301 else if ( strcmp(arg, "-include_all_dylibs_in_dir") == 0 ) {
302 includeAllDylibs = true;
303 }
304 else if ( strcmp(arg, "-env") == 0 ) {
305 const char* envArg = argv[++i];
306 if ( (envArg == nullptr) || (strchr(envArg, '=') == nullptr) ) {
307 fprintf(stderr, "-env option requires KEY=VALUE\n");
308 return 1;
309 }
310 envArgs.push_back(envArg);
311 }
312 else if ( strcmp(arg, "-use_closured") == 0 ) {
313 useClosured = true;
314 }
315 else {
316 fprintf(stderr, "unknown option %s\n", arg);
317 return 1;
318 }
319 }
320
321 if ( (inputMainExecutablePath || inputTopImagePath) && printPath ) {
322 fprintf(stderr, "-create_closure and -print_closure_file are mutually exclusive");
323 return 1;
324 }
325
326 const DyldSharedCache* dyldCache = nullptr;
327 bool dyldCacheIsRaw = false;
328 if ( cacheFilePath != nullptr ) {
329 dyldCache = mapCacheFile(cacheFilePath);
330 dyldCacheIsRaw = true;
331 }
332 else {
333 #if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)
334 size_t cacheLength;
335 dyldCache = (DyldSharedCache*)_dyld_get_shared_cache_range(&cacheLength);
336 dyldCacheIsRaw = false;
337 #endif
338 }
339 dyld3::ClosureBuffer::CacheIdent cacheIdent;
340 dyldCache->getUUID(cacheIdent.cacheUUID);
341 cacheIdent.cacheAddress = (unsigned long)dyldCache;
342 cacheIdent.cacheMappedSize = dyldCache->mappedSize();
343 dyld3::DyldCacheParser cacheParser(dyldCache, dyldCacheIsRaw);
344
345 if ( buildtimePrefixes.empty() )
346 buildtimePrefixes.push_back("");
347
348 std::vector<const dyld3::launch_cache::binary_format::ImageGroup*> existingGroups;
349 const dyld3::launch_cache::BinaryClosureData* mainClosure = nullptr;
350 if ( inputMainExecutablePath != nullptr ) {
351 dyld3::PathOverrides pathStuff(envArgs);
352 STACK_ALLOC_DYNARRAY(const dyld3::launch_cache::binary_format::ImageGroup*, 3+dlopens.size(), theGroups);
353 theGroups[0] = cacheParser.cachedDylibsGroup();
354 theGroups[1] = cacheParser.otherDylibsGroup();
355 dyld3::launch_cache::DynArray<const dyld3::launch_cache::binary_format::ImageGroup*> groupList(2, &theGroups[0]);
356 dyld3::ClosureBuffer clsBuffer(cacheIdent, inputMainExecutablePath, groupList, pathStuff);
357
358 std::string mainPath = inputMainExecutablePath;
359 for (const std::string& prefix : buildtimePrefixes) {
360 if ( startsWith(mainPath, prefix) ) {
361 mainPath = mainPath.substr(prefix.size());
362 if ( mainPath[0] != '/' )
363 mainPath = "/" + mainPath;
364 break;
365 }
366 }
367
368 Diagnostics closureDiag;
369 //if ( useClosured )
370 // mainClosure = closured_makeClosure(closureDiag, clsBuffer);
371 // else
372 mainClosure = dyld3::ImageProxyGroup::makeClosure(closureDiag, clsBuffer, mach_task_self(), buildtimePrefixes);
373 if ( closureDiag.hasError() ) {
374 fprintf(stderr, "dyld_closure_util: %s\n", closureDiag.errorMessage().c_str());
375 return 1;
376 }
377 for (const std::string& warn : closureDiag.warnings() )
378 fprintf(stderr, "dyld_closure_util: warning: %s\n", warn.c_str());
379
380 dyld3::launch_cache::Closure closure(mainClosure);
381 if ( outPath != nullptr ) {
382 safeSave(mainClosure, closure.size(), outPath);
383 }
384 else {
385 dyld3::launch_cache::Closure theClosure(mainClosure);
386 theGroups[2] = theClosure.group().binaryData();
387 if ( !dlopens.empty() )
388 printf("[\n");
389 closure.printAsJSON(dyld3::launch_cache::ImageGroupList(3, &theGroups[0]), true);
390
391 int groupIndex = 3;
392 for (const char* path : dlopens) {
393 printf(",\n");
394 dyld3::launch_cache::DynArray<const dyld3::launch_cache::binary_format::ImageGroup*> groupList2(groupIndex-2, &theGroups[2]);
395 dyld3::ClosureBuffer dlopenBuffer(cacheIdent, path, groupList2, pathStuff);
396 Diagnostics dlopenDiag;
397 //if ( useClosured )
398 // theGroups[groupIndex] = closured_makeDlopenGroup(closureDiag, clsBuffer);
399 //else
400 theGroups[groupIndex] = dyld3::ImageProxyGroup::makeDlopenGroup(dlopenDiag, dlopenBuffer, mach_task_self(), buildtimePrefixes);
401 if ( dlopenDiag.hasError() ) {
402 fprintf(stderr, "dyld_closure_util: %s\n", dlopenDiag.errorMessage().c_str());
403 return 1;
404 }
405 for (const std::string& warn : dlopenDiag.warnings() )
406 fprintf(stderr, "dyld_closure_util: warning: %s\n", warn.c_str());
407 dyld3::launch_cache::ImageGroup dlopenGroup(theGroups[groupIndex]);
408 dlopenGroup.printAsJSON(dyld3::launch_cache::ImageGroupList(groupIndex+1, &theGroups[0]), true);
409 ++groupIndex;
410 }
411 if ( !dlopens.empty() )
412 printf("]\n");
413 }
414
415 }
416 #if 0
417 else if ( inputTopImagePath != nullptr ) {
418 std::string imagePath = inputTopImagePath;
419 for (const std::string& prefix : buildtimePrefixes) {
420 if ( startsWith(imagePath, prefix) ) {
421 imagePath = imagePath.substr(prefix.size());
422 if ( imagePath[0] != '/' )
423 imagePath = "/" + imagePath;
424 break;
425 }
426 }
427
428 Diagnostics igDiag;
429 existingGroups.push_back(dyldCache->cachedDylibsGroup());
430 existingGroups.push_back(dyldCache->otherDylibsGroup());
431 if ( existingClosuresPath != nullptr ) {
432 size_t mappedSize;
433 const void* imageGroups = mapFileReadOnly(existingClosuresPath, mappedSize);
434 if ( imageGroups == nullptr ) {
435 fprintf(stderr, "dyld_closure_util: could not read file %s\n", printPath);
436 return 1;
437 }
438 uint32_t sentGroups = *(uint32_t*)imageGroups;
439 uint16_t lastGroupNum = 2;
440 existingGroups.resize(sentGroups+2);
441 const uint8_t* p = (uint8_t*)(imageGroups)+4;
442 //const uint8_t* end = (uint8_t*)(imageGroups) + mappedSize;
443 for (uint32_t i=0; i < sentGroups; ++i) {
444 const dyld3::launch_cache::binary_format::ImageGroup* aGroup = (const dyld3::launch_cache::binary_format::ImageGroup*)p;
445 existingGroups[2+i] = aGroup;
446 dyld3::launch_cache::ImageGroup imgrp(aGroup);
447 lastGroupNum = imgrp.groupNum();
448 p += imgrp.size();
449 }
450 }
451 const dyld3::launch_cache::binary_format::ImageGroup* ig = dyld3::ImageProxyGroup::makeDlopenGroup(igDiag, dyldCache, existingGroups.size(), existingGroups, imagePath, envArgs);
452 if ( igDiag.hasError() ) {
453 fprintf(stderr, "dyld_closure_util: %s\n", igDiag.errorMessage().c_str());
454 return 1;
455 }
456
457 dyld3::launch_cache::ImageGroup group(ig);
458 group.printAsJSON(dyldCache, true);
459 }
460 #endif
461 else if ( printPath != nullptr ) {
462 size_t mappedSize;
463 const void* buff = mapFileReadOnly(printPath, mappedSize);
464 if ( buff == nullptr ) {
465 fprintf(stderr, "dyld_closure_util: could not read file %s\n", printPath);
466 return 1;
467 }
468 dyld3::launch_cache::Closure theClosure((dyld3::launch_cache::binary_format::Closure*)buff);
469 STACK_ALLOC_DYNARRAY(const dyld3::launch_cache::binary_format::ImageGroup*, 3, theGroups);
470 theGroups[0] = cacheParser.cachedDylibsGroup();
471 theGroups[1] = cacheParser.otherDylibsGroup();
472 theGroups[2] = theClosure.group().binaryData();
473 theClosure.printAsJSON(theGroups, verboseFixups);
474 //closure.printStatistics();
475 munmap((void*)buff, mappedSize);
476 }
477 else if ( printGroupPath != nullptr ) {
478 size_t mappedSize;
479 const void* buff = mapFileReadOnly(printGroupPath, mappedSize);
480 if ( buff == nullptr ) {
481 fprintf(stderr, "dyld_closure_util: could not read file %s\n", printPath);
482 return 1;
483 }
484 dyld3::launch_cache::ImageGroup group((dyld3::launch_cache::binary_format::ImageGroup*)buff);
485 // group.printAsJSON(dyldCache, verboseFixups);
486 munmap((void*)buff, mappedSize);
487 }
488 else if ( listCacheClosures ) {
489 cacheParser.forEachClosure(^(const char* runtimePath, const dyld3::launch_cache::binary_format::Closure* closureBinary) {
490 dyld3::launch_cache::Closure closure(closureBinary);
491 printf("%6lu %s\n", closure.size(), runtimePath);
492 });
493 }
494 else if ( listOtherDylibs ) {
495 dyld3::launch_cache::ImageGroup dylibGroup(cacheParser.otherDylibsGroup());
496 for (uint32_t i=0; i < dylibGroup.imageCount(); ++i) {
497 dyld3::launch_cache::Image image = dylibGroup.image(i);
498 printf("%s\n", image.path());
499 }
500 }
501 else if ( printCacheClosure ) {
502 const dyld3::launch_cache::BinaryClosureData* cls = cacheParser.findClosure(printCacheClosure);
503 if ( cls != nullptr ) {
504 dyld3::launch_cache::Closure theClosure(cls);
505 STACK_ALLOC_DYNARRAY(const dyld3::launch_cache::binary_format::ImageGroup*, 3, theGroups);
506 theGroups[0] = cacheParser.cachedDylibsGroup();
507 theGroups[1] = cacheParser.otherDylibsGroup();
508 theGroups[2] = theClosure.group().binaryData();
509 theClosure.printAsJSON(theGroups, verboseFixups);
510 }
511 else {
512 fprintf(stderr, "no closure in cache for %s\n", printCacheClosure);
513 }
514 }
515 else if ( printClosures ) {
516 cacheParser.forEachClosure(^(const char* runtimePath, const dyld3::launch_cache::binary_format::Closure* closureBinary) {
517 dyld3::launch_cache::Closure theClosure(closureBinary);
518 STACK_ALLOC_DYNARRAY(const dyld3::launch_cache::binary_format::ImageGroup*, 3, theGroups);
519 theGroups[0] = cacheParser.cachedDylibsGroup();
520 theGroups[1] = cacheParser.otherDylibsGroup();
521 theGroups[2] = theClosure.group().binaryData();
522 theClosure.printAsJSON(theGroups, verboseFixups);
523 });
524 }
525 else if ( printCachedDylibs ) {
526 STACK_ALLOC_DYNARRAY(const dyld3::launch_cache::binary_format::ImageGroup*, 2, theGroups);
527 theGroups[0] = cacheParser.cachedDylibsGroup();
528 theGroups[1] = cacheParser.otherDylibsGroup();
529 dyld3::launch_cache::ImageGroup dylibGroup(theGroups[0]);
530 dylibGroup.printAsJSON(theGroups, verboseFixups);
531 }
532 else if ( printCachedDylib != nullptr ) {
533 STACK_ALLOC_DYNARRAY(const dyld3::launch_cache::binary_format::ImageGroup*, 2, theGroups);
534 theGroups[0] = cacheParser.cachedDylibsGroup();
535 theGroups[1] = cacheParser.otherDylibsGroup();
536 dyld3::launch_cache::ImageGroup dylibGroup(cacheParser.cachedDylibsGroup());
537 uint32_t imageIndex;
538 const dyld3::launch_cache::binary_format::Image* binImage = dylibGroup.findImageByPath(printCachedDylib, imageIndex);
539 if ( binImage != nullptr ) {
540 dyld3::launch_cache::Image image(binImage);
541 image.printAsJSON(theGroups, true);
542 }
543 else {
544 fprintf(stderr, "no such other image found\n");
545 }
546 }
547 else if ( printOtherDylibs ) {
548 STACK_ALLOC_DYNARRAY(const dyld3::launch_cache::binary_format::ImageGroup*, 2, theGroups);
549 theGroups[0] = cacheParser.cachedDylibsGroup();
550 theGroups[1] = cacheParser.otherDylibsGroup();
551 dyld3::launch_cache::ImageGroup dylibGroup(theGroups[1]);
552 dylibGroup.printAsJSON(theGroups, verboseFixups);
553 }
554 else if ( printOtherDylib != nullptr ) {
555 STACK_ALLOC_DYNARRAY(const dyld3::launch_cache::binary_format::ImageGroup*, 2, theGroups);
556 theGroups[0] = cacheParser.cachedDylibsGroup();
557 theGroups[1] = cacheParser.otherDylibsGroup();
558 dyld3::launch_cache::ImageGroup dylibGroup(cacheParser.otherDylibsGroup());
559 uint32_t imageIndex;
560 const dyld3::launch_cache::binary_format::Image* binImage = dylibGroup.findImageByPath(printOtherDylib, imageIndex);
561 if ( binImage != nullptr ) {
562 dyld3::launch_cache::Image image(binImage);
563 image.printAsJSON(theGroups, true);
564 }
565 else {
566 fprintf(stderr, "no such other image found\n");
567 }
568 }
569 else if ( printPatchTable ) {
570 __block uint64_t cacheBaseAddress = 0;
571 dyldCache->forEachRegion(^(const void* content, uint64_t vmAddr, uint64_t size, uint32_t permissions) {
572 if ( cacheBaseAddress == 0 )
573 cacheBaseAddress = vmAddr;
574 });
575 __block std::vector<CachedSections> sections;
576 __block bool hasError = false;
577 dyldCache->forEachImage(^(const mach_header* mh, const char* installName) {
578 dyld3::MachOParser parser(mh, dyldCacheIsRaw);
579 parser.forEachSection(^(const char* segName, const char* sectionName, uint32_t flags, uint64_t addr, const void* content,
580 uint64_t size, uint32_t alignP2, uint32_t reserved1, uint32_t reserved2, bool illegalSectionSize, bool& stop) {
581 if ( illegalSectionSize ) {
582 fprintf(stderr, "dyld_closure_util: section size extends beyond the end of the segment %s/%s\n", segName, sectionName);
583 stop = true;
584 return;
585 }
586 uint32_t offsetStart = (uint32_t)(addr - cacheBaseAddress);
587 uint32_t offsetEnd = (uint32_t)(offsetStart + size);
588 sections.push_back({offsetStart, offsetEnd, addr, mh, segName, sectionName, installName});
589 });
590 });
591 if (hasError)
592 return 1;
593 dyld3::launch_cache::ImageGroup dylibGroup(cacheParser.cachedDylibsGroup());
594 dylibGroup.forEachDyldCachePatchLocation(cacheParser, ^(uint32_t targetCacheVmOffset, const std::vector<uint32_t>& usesPointersCacheVmOffsets, bool& stop) {
595 const CachedSections& targetSection = find(targetCacheVmOffset, sections);
596 dyld3::MachOParser targetParser(targetSection.mh, dyldCacheIsRaw);
597 const char* symbolName;
598 uint64_t symbolAddress;
599 if ( targetParser.findClosestSymbol(targetSection.vmAddress + targetCacheVmOffset - targetSection.mappedOffsetStart, &symbolName, &symbolAddress) ) {
600 printf("%s: [cache offset = 0x%08X]\n", symbolName, targetCacheVmOffset);
601 }
602 else {
603 printf("0x%08X from %40s %10s %16s + 0x%06X\n", targetCacheVmOffset, strrchr(targetSection.dylibPath, '/')+1, targetSection.segmentName.c_str(), targetSection.sectionName.c_str(), targetCacheVmOffset - targetSection.mappedOffsetStart);
604 }
605 for (uint32_t offset : usesPointersCacheVmOffsets) {
606 const CachedSections& usedInSection = find(offset, sections);
607 printf("%40s %10s %16s + 0x%06X\n", strrchr(usedInSection.dylibPath, '/')+1, usedInSection.segmentName.c_str(), usedInSection.sectionName.c_str(), offset - usedInSection.mappedOffsetStart);
608 }
609 });
610 }
611
612
613 return 0;
614 }