2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
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>
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"
54 #include "closuredProtocol.h"
57 static const DyldSharedCache
* mapCacheFile(const char* path
)
60 if (stat(path
, &statbuf
)) {
61 fprintf(stderr
, "Error: stat failed for dyld shared cache at %s\n", path
);
65 int cache_fd
= open(path
, O_RDONLY
);
67 fprintf(stderr
, "Error: failed to open shared cache file at %s\n", path
);
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
);
78 return (DyldSharedCache
*)mapped_cache
;
83 uint32_t mappedOffsetStart
;
84 uint32_t mappedOffsetEnd
;
86 const mach_header
* mh
;
87 std::string segmentName
;
88 std::string sectionName
;
89 const char* dylibPath
;
92 static const CachedSections
& find(uint32_t mappedOffset
, const std::vector
<CachedSections
>& sections
)
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
) )
99 assert(0 && "invalid offset");
103 static const dyld3::launch_cache::BinaryClosureData*
104 callClosureDaemon(const std::string& mainPath, const std::string& cachePath, const std::vector<std::string>& envArgs)
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);
112 case BOOTSTRAP_SUCCESS :
113 // service currently registered, "a good thing" (tm)
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));
120 // service not currently registered, try again later
121 fprintf(stderr, "bootstrap_look_up(): %s [%d]\n", mach_error_string(kr), kr);
125 //printf("serverPort=%d, replyPort=%d\n", serverPort, replyPort);
130 char envBuffer[2048];
131 vm_offset_t reply = 0;
132 uint32_t replySize = 0;
135 // kr = closured_CreateLaunchClosure(serverPort, mainPath.c_str(), cachePath.c_str(), uuid, envBuffer, &success, &reply, &replySize);
137 printf("success=%d, buf=%p, bufLen=%d\n", success, (void*)reply, replySize);
141 return (const dyld3::launch_cache::BinaryClosureData*)reply;
147 printf("dyld_closure_util program to create of view dyld3 closures\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");
170 int main(int argc
, const char* argv
[])
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
;
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");
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");
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");
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");
228 dlopens
.push_back(path
);
230 else if ( strcmp(arg
, "-verbose_fixups") == 0 ) {
231 verboseFixups
= true;
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");
239 buildtimePrefixes
.push_back(buildRootPath
);
241 else if ( strcmp(arg
, "-o") == 0 ) {
243 if ( outPath
== nullptr ) {
244 fprintf(stderr
, "-o option requires a path \n");
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");
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");
262 else if ( strcmp(arg
, "-list_dyld_cache_closures") == 0 ) {
263 listCacheClosures
= true;
265 else if ( strcmp(arg
, "-list_dyld_cache_other_dylibs") == 0 ) {
266 listOtherDylibs
= true;
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");
275 else if ( strcmp(arg
, "-print_dyld_cache_closures") == 0 ) {
276 printClosures
= true;
278 else if ( strcmp(arg
, "-print_dyld_cache_dylibs") == 0 ) {
279 printCachedDylibs
= true;
281 else if ( strcmp(arg
, "-print_dyld_cache_other_dylibs") == 0 ) {
282 printOtherDylibs
= true;
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");
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");
298 else if ( strcmp(arg
, "-print_dyld_cache_patch_table") == 0 ) {
299 printPatchTable
= true;
301 else if ( strcmp(arg
, "-include_all_dylibs_in_dir") == 0 ) {
302 includeAllDylibs
= true;
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");
310 envArgs
.push_back(envArg
);
312 else if ( strcmp(arg
, "-use_closured") == 0 ) {
316 fprintf(stderr
, "unknown option %s\n", arg
);
321 if ( (inputMainExecutablePath
|| inputTopImagePath
) && printPath
) {
322 fprintf(stderr
, "-create_closure and -print_closure_file are mutually exclusive");
326 const DyldSharedCache
* dyldCache
= nullptr;
327 bool dyldCacheIsRaw
= false;
328 if ( cacheFilePath
!= nullptr ) {
329 dyldCache
= mapCacheFile(cacheFilePath
);
330 dyldCacheIsRaw
= true;
333 #if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)
335 dyldCache
= (DyldSharedCache
*)_dyld_get_shared_cache_range(&cacheLength
);
336 dyldCacheIsRaw
= false;
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
);
345 if ( buildtimePrefixes
.empty() )
346 buildtimePrefixes
.push_back("");
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
);
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
;
368 Diagnostics closureDiag
;
370 // mainClosure = closured_makeClosure(closureDiag, clsBuffer);
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());
377 for (const std::string
& warn
: closureDiag
.warnings() )
378 fprintf(stderr
, "dyld_closure_util: warning: %s\n", warn
.c_str());
380 dyld3::launch_cache::Closure
closure(mainClosure
);
381 if ( outPath
!= nullptr ) {
382 safeSave(mainClosure
, closure
.size(), outPath
);
385 dyld3::launch_cache::Closure
theClosure(mainClosure
);
386 theGroups
[2] = theClosure
.group().binaryData();
387 if ( !dlopens
.empty() )
389 closure
.printAsJSON(dyld3::launch_cache::ImageGroupList(3, &theGroups
[0]), true);
392 for (const char* path
: dlopens
) {
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
;
398 // theGroups[groupIndex] = closured_makeDlopenGroup(closureDiag, clsBuffer);
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());
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);
411 if ( !dlopens
.empty() )
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
;
429 existingGroups
.push_back(dyldCache
->cachedDylibsGroup());
430 existingGroups
.push_back(dyldCache
->otherDylibsGroup());
431 if ( existingClosuresPath
!= nullptr ) {
433 const void* imageGroups
= mapFileReadOnly(existingClosuresPath
, mappedSize
);
434 if ( imageGroups
== nullptr ) {
435 fprintf(stderr
, "dyld_closure_util: could not read file %s\n", printPath
);
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();
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());
457 dyld3::launch_cache::ImageGroup
group(ig
);
458 group
.printAsJSON(dyldCache
, true);
461 else if ( printPath
!= nullptr ) {
463 const void* buff
= mapFileReadOnly(printPath
, mappedSize
);
464 if ( buff
== nullptr ) {
465 fprintf(stderr
, "dyld_closure_util: could not read file %s\n", printPath
);
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
);
477 else if ( printGroupPath
!= nullptr ) {
479 const void* buff
= mapFileReadOnly(printGroupPath
, mappedSize
);
480 if ( buff
== nullptr ) {
481 fprintf(stderr
, "dyld_closure_util: could not read file %s\n", printPath
);
484 dyld3::launch_cache::ImageGroup
group((dyld3::launch_cache::binary_format::ImageGroup
*)buff
);
485 // group.printAsJSON(dyldCache, verboseFixups);
486 munmap((void*)buff
, mappedSize
);
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
);
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());
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
);
512 fprintf(stderr
, "no closure in cache for %s\n", printCacheClosure
);
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
);
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
);
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());
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);
544 fprintf(stderr
, "no such other image found\n");
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
);
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());
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);
566 fprintf(stderr
, "no such other image found\n");
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
;
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
);
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
});
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
);
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
);
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
);