1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 * Copyright (c) 2018 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
28 #include <mach/mach.h>
29 #include <mach/mach_time.h>
30 #include <mach-o/dyld.h>
43 #include <sys/param.h>
44 #include <sys/sysctl.h>
45 #include <sys/resource.h>
49 #include <dispatch/dispatch.h>
50 #include <pthread/pthread.h>
51 #include <CoreFoundation/CoreFoundation.h>
55 #include <unordered_set>
56 #include <unordered_set>
60 #include "FileUtils.h"
61 #include "StringUtils.h"
62 #include "DyldSharedCache.h"
63 #include "MachOFile.h"
64 #include "MachOAnalyzer.h"
65 #include "ClosureFileSystemPhysical.h"
67 struct MappedMachOsByCategory
69 const dyld3::GradedArchs
& archs
;
70 std::vector
<DyldSharedCache::MappedMachO
> dylibsForCache
;
71 std::vector
<DyldSharedCache::MappedMachO
> otherDylibsAndBundles
;
72 std::vector
<DyldSharedCache::MappedMachO
> mainExecutables
;
75 static const char* sAllowedPrefixes
[] = {
78 // don't look at main executables until simulator supports dyld3
83 static const char* sDontUsePrefixes
[] = {
88 static const char* sMacOSHostLibs
[] = {
89 "/usr/lib/system/libsystem_kernel.dylib",
90 "/usr/lib/system/libsystem_platform.dylib",
91 "/usr/lib/system/libsystem_pthread.dylib",
94 static const char* sMacOSBinaries
[] = {
95 "/sbin/launchd_sim_trampoline",
96 "/usr/sbin/iokitsimd",
97 "/usr/lib/system/host/liblaunch_sim.dylib",
100 static bool verbose
= false;
103 static bool addIfMachO(const dyld3::closure::FileSystem
& fileSystem
, const std::string
& runtimePath
, const struct stat
& statBuf
, std::vector
<MappedMachOsByCategory
>& files
, dyld3::Platform platform
)
105 // don't precompute closure info for any debug or profile dylibs
106 if ( endsWith(runtimePath
, "_profile.dylib") || endsWith(runtimePath
, "_debug.dylib") || endsWith(runtimePath
, "_asan.dylib") || endsWith(runtimePath
, "_profile") || endsWith(runtimePath
, "_debug") )
108 if ( startsWith(runtimePath
, "/usr/lib/system/introspection/") )
112 for (MappedMachOsByCategory
& file
: files
) {
114 char realerPath
[MAXPATHLEN
];
115 dyld3::closure::LoadedFileInfo loadedFileInfo
= dyld3::MachOAnalyzer::load(diag
, fileSystem
, runtimePath
.c_str(), file
.archs
, platform
, realerPath
);
116 const dyld3::MachOAnalyzer
* ma
= (const dyld3::MachOAnalyzer
*)loadedFileInfo
.fileContent
;
118 if ( ma
!= nullptr ) {
119 bool sipProtected
= false; // isProtectedBySIP(fd);
120 bool issetuid
= false;
121 const uint64_t sliceLen
= loadedFileInfo
.sliceLen
;
122 if ( ma
->isDynamicExecutable() ) {
123 #if 0 // dyld3 not enabled for simulator yet, so don't collect main executables
124 issetuid
= (statBuf
.st_mode
& (S_ISUID
|S_ISGID
));
125 file
.mainExecutables
.emplace_back(runtimePath
, ma
, sliceLen
, issetuid
, sipProtected
, loadedFileInfo
.sliceOffset
, statBuf
.st_mtime
, statBuf
.st_ino
);
129 else if ( ma
->canBePlacedInDyldCache(runtimePath
.c_str(), ^(const char* msg
) {}) ) {
130 file
.dylibsForCache
.emplace_back(runtimePath
, ma
, sliceLen
, issetuid
, sipProtected
, loadedFileInfo
.sliceOffset
, statBuf
.st_mtime
, statBuf
.st_ino
);
139 static void findAllFiles(const dyld3::closure::FileSystem
& fileSystem
, const std::vector
<std::string
>& pathPrefixes
, std::vector
<MappedMachOsByCategory
>& files
, dyld3::Platform platform
)
141 std::unordered_set
<std::string
> skipDirs
;
142 for (const char* s
: sDontUsePrefixes
)
145 __block
std::unordered_set
<std::string
> alreadyUsed
;
146 bool multiplePrefixes
= (pathPrefixes
.size() > 1);
147 for (const std::string
& prefix
: pathPrefixes
) {
148 // get all files from overlay for this search dir
149 for (const char* searchDir
: sAllowedPrefixes
) {
150 iterateDirectoryTree(prefix
, searchDir
, ^(const std::string
& dirPath
) { return (skipDirs
.count(dirPath
) != 0); }, ^(const std::string
& path
, const struct stat
& statBuf
) {
151 // ignore files that don't have 'x' bit set (all runnable mach-o files do)
152 const bool hasXBit
= ((statBuf
.st_mode
& S_IXOTH
) == S_IXOTH
);
153 if ( !hasXBit
&& !endsWith(path
, ".dylib") )
156 // ignore files too small (must have at least a page of TEXT and LINKEDIT)
157 if ( statBuf
.st_size
< 0x2000 )
160 // don't add paths already found using previous prefix
161 if ( multiplePrefixes
&& (alreadyUsed
.count(path
) != 0) )
164 // don't add binaries built for the host Mac OS platform
165 for (std::string s
: sMacOSBinaries
) {
166 if (s
.compare(path
) == 0)
169 // if the file is mach-o, add to list
170 if ( addIfMachO(fileSystem
, path
, statBuf
, files
, platform
) ) {
171 if ( multiplePrefixes
)
172 alreadyUsed
.insert(path
);
179 static void addMacOSHostLibs(std::vector
<MappedMachOsByCategory
>& allFileSets
, dyld3::Platform platform
)
181 dyld3::closure::FileSystemPhysical fileSystem
;
182 for (const char* path
: sMacOSHostLibs
) {
184 if ( stat(path
, &statBuf
) == 0 ) {
185 addIfMachO(fileSystem
, path
, statBuf
, allFileSets
, dyld3::Platform::macOS
);
190 static void addMacOSBinaries(const dyld3::closure::FileSystem
& fileSystem
, const std::vector
<std::string
>& pathPrefixes
, std::vector
<MappedMachOsByCategory
>& files
)
192 for (const std::string
& prefix
: pathPrefixes
) {
193 for (std::string path
: sMacOSBinaries
) {
194 std::string fullPath
= prefix
+ path
;
196 if ( stat(fullPath
.c_str(), &statBuf
) == 0 ) {
197 addIfMachO(fileSystem
, path
, statBuf
, files
, dyld3::Platform::macOS
);
203 static bool dontCache(const std::string
& simRuntimeRootPath
, const std::string
& archName
,
204 const std::unordered_set
<std::string
>& pathsWithDuplicateInstallName
,
205 const DyldSharedCache::MappedMachO
& aFile
, bool warn
,
206 const std::unordered_set
<std::string
>& skipDylibs
)
208 if ( skipDylibs
.count(aFile
.runtimePath
) )
210 if ( startsWith(aFile
.runtimePath
, "/usr/lib/system/introspection/") )
212 if ( startsWith(aFile
.runtimePath
, "/usr/local/") )
215 // anything inside a .app bundle is specific to app, so should not be in shared cache
216 if ( aFile
.runtimePath
.find(".app/") != std::string::npos
)
219 if ( archName
== "i386" ) {
220 if ( startsWith(aFile
.runtimePath
, "/System/Library/CoreServices/") )
222 if ( startsWith(aFile
.runtimePath
, "/System/Library/Extensions/") )
226 if ( aFile
.runtimePath
.find("//") != std::string::npos
) {
227 if (warn
) fprintf(stderr
, "update_dyld_sim_shared_cache: warning: %s use of bad install name %s\n", archName
.c_str(), aFile
.runtimePath
.c_str());
231 const char* installName
= aFile
.mh
->installName();
232 if ( (pathsWithDuplicateInstallName
.count(aFile
.runtimePath
) != 0) && (aFile
.runtimePath
!= installName
) ) {
233 // <rdar://problem/46431467> if a dylib moves and a symlink is installed into its place, bom iterator will see both and issue a warning
235 bool isSymLink
= ( (lstat(aFile
.runtimePath
.c_str(), &statBuf
) == 0) && S_ISLNK(statBuf
.st_mode
) );
236 if (!isSymLink
&& warn
) fprintf(stderr
, "update_dyld_sim_shared_cache: warning: %s skipping because of duplicate install name %s\n", archName
.c_str(), aFile
.runtimePath
.c_str());
240 if ( aFile
.runtimePath
!= installName
) {
241 // see if install name is a symlink to actual path
242 std::string fullInstall
= simRuntimeRootPath
+ installName
;
243 char resolvedPath
[PATH_MAX
];
244 if ( realpath(fullInstall
.c_str(), resolvedPath
) != NULL
) {
245 std::string resolvedSymlink
= resolvedPath
;
246 if ( !simRuntimeRootPath
.empty() ) {
247 resolvedSymlink
= resolvedSymlink
.substr(simRuntimeRootPath
.size());
249 if ( aFile
.runtimePath
== resolvedSymlink
) {
253 // <rdar://problem/38000411> also if runtime path is a symlink to install name
254 std::string fullRuntime
= simRuntimeRootPath
+ aFile
.runtimePath
;
255 if ( realpath(fullRuntime
.c_str(), resolvedPath
) != NULL
) {
256 std::string resolvedSymlink
= resolvedPath
;
257 if ( !simRuntimeRootPath
.empty() ) {
258 resolvedSymlink
= resolvedSymlink
.substr(simRuntimeRootPath
.size());
260 if ( resolvedSymlink
== installName
) {
264 if (warn
) fprintf(stderr
, "update_dyld_sim_shared_cache: warning: %s skipping because of bad install name %s\n", archName
.c_str(), aFile
.runtimePath
.c_str());
270 static void pruneCachedDylibs(const std::string
& volumePrefix
, const std::unordered_set
<std::string
>& skipDylibs
, MappedMachOsByCategory
& fileSet
)
272 std::unordered_set
<std::string
> pathsWithDuplicateInstallName
;
274 std::unordered_map
<std::string
, std::string
> installNameToFirstPath
;
275 for (DyldSharedCache::MappedMachO
& aFile
: fileSet
.dylibsForCache
) {
276 const char* installName
= aFile
.mh
->installName();
277 auto pos
= installNameToFirstPath
.find(installName
);
278 if ( pos
== installNameToFirstPath
.end() ) {
279 installNameToFirstPath
[installName
] = aFile
.runtimePath
;
282 pathsWithDuplicateInstallName
.insert(aFile
.runtimePath
);
283 pathsWithDuplicateInstallName
.insert(installNameToFirstPath
[installName
]);
287 for (DyldSharedCache::MappedMachO
& aFile
: fileSet
.dylibsForCache
) {
288 if ( dontCache(volumePrefix
, fileSet
.archs
.name(), pathsWithDuplicateInstallName
, aFile
, true, skipDylibs
) ){
289 // <rdar://problem/46423929> don't build dlopen closures for symlinks to something in the dyld cache
290 if ( pathsWithDuplicateInstallName
.count(aFile
.runtimePath
) == 0 )
291 fileSet
.otherDylibsAndBundles
.push_back(aFile
);
294 fileSet
.dylibsForCache
.erase(std::remove_if(fileSet
.dylibsForCache
.begin(), fileSet
.dylibsForCache
.end(),
295 [&](const DyldSharedCache::MappedMachO
& aFile
) { return dontCache(volumePrefix
, fileSet
.archs
.name(), pathsWithDuplicateInstallName
, aFile
, false, skipDylibs
); }),
296 fileSet
.dylibsForCache
.end());
299 static void pruneOtherDylibs(const std::string
& volumePrefix
, MappedMachOsByCategory
& fileSet
)
301 // other OS dylibs should not contain dylibs that are embedded in some .app bundle
302 fileSet
.otherDylibsAndBundles
.erase(std::remove_if(fileSet
.otherDylibsAndBundles
.begin(), fileSet
.otherDylibsAndBundles
.end(),
303 [&](const DyldSharedCache::MappedMachO
& aFile
) { return (aFile
.runtimePath
.find(".app/") != std::string::npos
); }),
304 fileSet
.otherDylibsAndBundles
.end());
308 static bool existingCacheUpToDate(const std::string
& existingCache
, const std::vector
<DyldSharedCache::MappedMachO
>& currentDylibs
)
310 // if no existing cache, it is not up-to-date
311 int fd
= ::open(existingCache
.c_str(), O_RDONLY
);
315 if ( ::fstat(fd
, &statbuf
) == -1 ) {
320 // build map of found dylibs
321 std::unordered_map
<std::string
, const DyldSharedCache::MappedMachO
*> currentDylibMap
;
322 for (const DyldSharedCache::MappedMachO
& aFile
: currentDylibs
) {
323 //fprintf(stderr, "0x%0llX 0x%0llX %s\n", aFile.inode, aFile.modTime, aFile.runtimePath.c_str());
324 currentDylibMap
[aFile
.runtimePath
] = &aFile
;
327 // make sure all dylibs in existing cache have same mtime and inode as found dylib
328 __block
bool foundMismatch
= false;
329 const uint64_t cacheMapLen
= statbuf
.st_size
;
330 void *p
= ::mmap(NULL
, cacheMapLen
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
331 if ( p
!= MAP_FAILED
) {
332 const DyldSharedCache
* cache
= (DyldSharedCache
*)p
;
333 cache
->forEachImageEntry(^(const char* installName
, uint64_t mTime
, uint64_t inode
) {
334 bool foundMatch
= false;
335 auto pos
= currentDylibMap
.find(installName
);
336 if ( pos
!= currentDylibMap
.end() ) {
337 const DyldSharedCache::MappedMachO
* foundDylib
= pos
->second
;
338 if ( (foundDylib
->inode
== inode
) && (foundDylib
->modTime
== mTime
) ) {
343 // use slow path and look for any dylib with a matching inode and mtime
344 bool foundSlow
= false;
345 for (const DyldSharedCache::MappedMachO
& aFile
: currentDylibs
) {
346 if ( (aFile
.inode
== inode
) && (aFile
.modTime
== mTime
) ) {
352 foundMismatch
= true;
354 fprintf(stderr
, "rebuilding dyld cache because dylib changed: %s\n", installName
);
358 ::munmap(p
, cacheMapLen
);
363 return !foundMismatch
;
367 inline uint32_t absolutetime_to_milliseconds(uint64_t abstime
)
369 return (uint32_t)(abstime
/1000/1000);
373 #define TERMINATE_IF_LAST_ARG( s ) \
375 if ( i == argc - 1 ) { \
376 fprintf(stderr, s ); \
381 int main(int argc
, const char* argv
[], const char* envp
[])
383 std::string rootPath
;
385 bool dylibsRemoved
= false;
386 std::string cacheDir
;
387 std::string dylibOrderFile
;
388 std::string dirtyDataOrderFile
;
389 dyld3::Platform platform
= dyld3::Platform::iOS_simulator
;
390 std::unordered_set
<std::string
> skipDylibs
;
392 // parse command line options
393 for (int i
= 1; i
< argc
; ++i
) {
394 const char* arg
= argv
[i
];
395 if (strcmp(arg
, "-debug") == 0) {
398 else if (strcmp(arg
, "-verbose") == 0) {
401 else if ((strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0)) {
402 TERMINATE_IF_LAST_ARG("-root missing path argument\n");
403 rootPath
= argv
[++i
];
405 else if (strcmp(arg
, "-cache_dir") == 0) {
406 TERMINATE_IF_LAST_ARG("-cache_dir missing path argument\n");
407 cacheDir
= argv
[++i
];
409 else if (strcmp(arg
, "-iOS") == 0) {
410 platform
= dyld3::Platform::iOS_simulator
;
412 else if (strcmp(arg
, "-watchOS") == 0) {
413 platform
= dyld3::Platform::watchOS_simulator
;
415 else if (strcmp(arg
, "-tvOS") == 0) {
416 platform
= dyld3::Platform::tvOS_simulator
;
418 else if (strcmp(arg
, "-dylibs_removed_in_mastering") == 0) {
419 dylibsRemoved
= true;
421 else if (strcmp(arg
, "-dylib_order_file") == 0) {
422 TERMINATE_IF_LAST_ARG("-dylib_order_file missing path argument\n");
423 dylibOrderFile
= argv
[++i
];
425 else if (strcmp(arg
, "-dirty_data_order_file") == 0) {
426 TERMINATE_IF_LAST_ARG("-dirty_data_order_file missing path argument\n");
427 dirtyDataOrderFile
= argv
[++i
];
429 else if (strcmp(arg
, "-force") == 0) {
432 else if (strcmp(arg
, "-skip") == 0) {
433 TERMINATE_IF_LAST_ARG("-skip missing argument\n");
434 skipDylibs
.insert(argv
[++i
]);
438 fprintf(stderr
, "update_dyld_sim_shared_cache: unknown option: %s\n", arg
);
443 if ( rootPath
.empty()) {
444 fprintf(stderr
, "-root should be specified\n");
447 if (cacheDir
.empty()) {
448 fprintf(stderr
, "-cache_dir should be specified\n");
451 // canonicalize rootPath
452 char resolvedPath
[PATH_MAX
];
453 if ( realpath(rootPath
.c_str(), resolvedPath
) != NULL
) {
454 rootPath
= resolvedPath
;
457 // Find the boot volume so that we can ensure all overlays are on the same volume
458 struct stat rootStatBuf
;
459 if ( stat(rootPath
.c_str(), &rootStatBuf
) != 0 ) {
460 fprintf(stderr
, "update_dyld_sim_shared_cache: error: could not stat root file system because '%s'\n", strerror(errno
));
464 std::vector
<std::string
> pathPrefixes
;
466 pathPrefixes
.push_back(rootPath
);
468 // build FileSystem object
469 const char* fsRoot
= rootPath
.empty() ? nullptr : rootPath
.c_str();
470 dyld3::closure::FileSystemPhysical
fileSystem(fsRoot
, nullptr);
473 int err
= mkpath_np(cacheDir
.c_str(), S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
);
474 if ( (err
!= 0) && (err
!= EEXIST
) ) {
475 fprintf(stderr
, "update_dyld_sim_shared_cache: could not access cache dir: mkpath_np(%s) failed errno=%d\n", cacheDir
.c_str(), err
);
479 uint64_t t1
= mach_absolute_time();
481 __block
std::vector
<MappedMachOsByCategory
> allFileSets
;
482 switch ( platform
) {
483 case dyld3::Platform::iOS_simulator
:
484 allFileSets
.push_back({dyld3::GradedArchs::x86_64
});
486 case dyld3::Platform::watchOS_simulator
:
487 allFileSets
.push_back({dyld3::GradedArchs::i386
});
489 case dyld3::Platform::tvOS_simulator
:
490 allFileSets
.push_back({dyld3::GradedArchs::x86_64
});
493 assert(0 && "invalid platform");
496 findAllFiles(fileSystem
, pathPrefixes
, allFileSets
, platform
);
497 addMacOSHostLibs(allFileSets
, platform
);
498 addMacOSBinaries(fileSystem
, pathPrefixes
, allFileSets
);
500 // nothing in OS uses i386 dylibs, so only dylibs used by third party apps need to be in cache
501 for (MappedMachOsByCategory
& fileSet
: allFileSets
) {
502 pruneCachedDylibs(rootPath
, skipDylibs
, fileSet
);
503 pruneOtherDylibs(rootPath
, fileSet
);
506 uint64_t t2
= mach_absolute_time();
508 fprintf(stderr
, "time to scan file system and construct lists of mach-o files: %ums\n", absolutetime_to_milliseconds(t2
-t1
));
511 // build caches in parallel on machines with at leat 4GB of RAM
512 uint64_t memSize
= 0;
513 size_t sz
= sizeof(memSize
);;
514 bool buildInParallel
= false;
515 if ( sysctlbyname("hw.memsize", &memSize
, &sz
, NULL
, 0) == 0 ) {
516 if ( memSize
>= 0x100000000ULL
)
517 buildInParallel
= true;
519 dispatch_queue_t dqueue
= buildInParallel
? dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0)
520 : dispatch_queue_create("serial-queue", DISPATCH_QUEUE_SERIAL
);
523 __block
bool cacheBuildFailure
= false;
524 __block
bool wroteSomeCacheFile
= false;
525 dispatch_apply(allFileSets
.size(), dqueue
, ^(size_t index
) {
526 MappedMachOsByCategory
& fileSet
= allFileSets
[index
];
527 const std::string outFile
= cacheDir
+ "/dyld_sim_shared_cache_" + fileSet
.archs
.name();
529 DyldSharedCache::MappedMachO (^loader
)(const std::string
&) = ^DyldSharedCache::MappedMachO(const std::string
& runtimePath
) {
530 if ( skipDylibs
.count(runtimePath
) )
531 return DyldSharedCache::MappedMachO();
533 for (const std::string
& prefix
: pathPrefixes
) {
534 std::string fullPath
= prefix
+ runtimePath
;
536 if ( stat(fullPath
.c_str(), &statBuf
) == 0 ) {
537 char truePath
[PATH_MAX
];
538 if ( realpath(fullPath
.c_str(), truePath
) != NULL
) {
539 std::string resolvedSymlink
= truePath
;
540 if ( !rootPath
.empty() ) {
541 resolvedSymlink
= resolvedSymlink
.substr(rootPath
.size());
543 if ( (runtimePath
!= resolvedSymlink
) && !contains(runtimePath
, "InputContext") ) { //HACK remove InputContext when fixed
544 // path requested is a symlink path, check if real path already loaded
545 for (const DyldSharedCache::MappedMachO
& aDylibMapping
: fileSet
.dylibsForCache
) {
546 if ( aDylibMapping
.runtimePath
== resolvedSymlink
) {
548 fprintf(stderr
, "verifySelfContained, redirect %s to %s\n", runtimePath
.c_str(), aDylibMapping
.runtimePath
.c_str());
549 return aDylibMapping
;
555 std::vector
<MappedMachOsByCategory
> mappedFiles
;
556 mappedFiles
.push_back({fileSet
.archs
});
557 if ( addIfMachO(fileSystem
, runtimePath
, statBuf
, mappedFiles
, platform
) ) {
558 if ( !mappedFiles
.back().dylibsForCache
.empty() ) {
560 fprintf(stderr
, "verifySelfContained, add %s\n", mappedFiles
.back().dylibsForCache
.back().runtimePath
.c_str());
561 return mappedFiles
.back().dylibsForCache
.back();
566 return DyldSharedCache::MappedMachO();
568 size_t startCount
= fileSet
.dylibsForCache
.size();
569 std::vector
<std::pair
<DyldSharedCache::MappedMachO
, std::set
<std::string
>>> excludes
;
570 std::unordered_set
<std::string
> badZippered
;
571 DyldSharedCache::verifySelfContained(fileSet
.dylibsForCache
, badZippered
, loader
, excludes
);
572 for (size_t i
=startCount
; i
< fileSet
.dylibsForCache
.size(); ++i
) {
573 fprintf(stderr
, "update_dyld_sim_shared_cache: warning: %s not in initial scan, but adding required dylib %s\n", fileSet
.archs
.name(), fileSet
.dylibsForCache
[i
].runtimePath
.c_str());
575 for (auto& exclude
: excludes
) {
576 std::string reasons
= "(\"";
577 for (auto i
= exclude
.second
.begin(); i
!= exclude
.second
.end(); ++i
) {
579 if (i
!= --exclude
.second
.end()) {
584 fprintf(stderr
, "update_dyld_shared_cache: warning: %s rejected from cached dylibs: %s (%s)\n", fileSet
.archs
.name(), exclude
.first
.runtimePath
.c_str(), reasons
.c_str());
585 fileSet
.otherDylibsAndBundles
.push_back(exclude
.first
);
588 // check if cache is already up to date
590 if ( existingCacheUpToDate(outFile
, fileSet
.dylibsForCache
) )
595 // build cache new cache file
596 DyldSharedCache::CreateOptions options
;
597 options
.outputFilePath
= outFile
;
598 options
.outputMapFilePath
= cacheDir
+ "/dyld_sim_shared_cache_" + fileSet
.archs
.name() + ".map";
599 options
.archs
= &fileSet
.archs
;
600 options
.platform
= platform
;
601 options
.excludeLocalSymbols
= false;
602 options
.optimizeStubs
= false;
603 options
.optimizeObjC
= true;
604 options
.codeSigningDigestMode
= DyldSharedCache::SHA256only
;
605 options
.dylibsRemovedDuringMastering
= dylibsRemoved
;
606 options
.inodesAreSameAsRuntime
= true;
607 options
.cacheSupportsASLR
= false;
608 options
.forSimulator
= true;
609 options
.isLocallyBuiltCache
= true;
610 options
.verbose
= verbose
;
611 options
.evictLeafDylibsOnOverflow
= true;
612 options
.dylibOrdering
= parseOrderFile(dylibOrderFile
);
613 options
.dirtyDataSegmentOrdering
= parseOrderFile(dirtyDataOrderFile
);
614 DyldSharedCache::CreateResults results
= DyldSharedCache::create(options
, fileSystem
, fileSet
.dylibsForCache
, fileSet
.otherDylibsAndBundles
, fileSet
.mainExecutables
);
616 // print any warnings
617 for (const std::string
& warn
: results
.warnings
) {
618 fprintf(stderr
, "update_dyld_sim_shared_cache: warning: %s %s\n", fileSet
.archs
.name(), warn
.c_str());
620 if ( results
.errorMessage
.empty() ) {
621 wroteSomeCacheFile
= true;
624 fprintf(stderr
, "update_dyld_sim_shared_cache: %s\n", results
.errorMessage
.c_str());
625 cacheBuildFailure
= true;
629 // we could unmap all input files, but tool is about to quit
631 return (cacheBuildFailure
? 1 : 0);