Loading...
dyld3/shared-cache/update_dyld_sim_shared_cache.cpp dyld-750.5 dyld-851.27
--- dyld/dyld-750.5/dyld3/shared-cache/update_dyld_sim_shared_cache.cpp
+++ dyld/dyld-851.27/dyld3/shared-cache/update_dyld_sim_shared_cache.cpp
@@ -56,6 +56,7 @@
 #include <unordered_set>
 #include <iostream>
 #include <fstream>
+#include <sstream>
 
 #include "FileUtils.h"
 #include "StringUtils.h"
@@ -100,7 +101,7 @@
 static bool verbose = false;
 
 
-static bool addIfMachO(const dyld3::closure::FileSystem& fileSystem, const std::string& runtimePath, const struct stat& statBuf, std::vector<MappedMachOsByCategory>& files, dyld3::Platform platform)
+static bool addIfMachO(const dyld3::closure::FileSystem& fileSystem, const std::string& runtimePath, const struct stat& statBuf, std::vector<MappedMachOsByCategory>& files, dyld3::Platform platform, Diagnostics& diag)
 {
     // don't precompute closure info for any debug or profile dylibs
     if ( endsWith(runtimePath, "_profile.dylib") || endsWith(runtimePath, "_debug.dylib") || endsWith(runtimePath, "_asan.dylib") || endsWith(runtimePath, "_profile") || endsWith(runtimePath, "_debug") )
@@ -110,13 +111,12 @@
 
     bool result = false;
     for (MappedMachOsByCategory& file : files) {
-        Diagnostics diag;
         char realerPath[MAXPATHLEN];
         dyld3::closure::LoadedFileInfo loadedFileInfo = dyld3::MachOAnalyzer::load(diag, fileSystem, runtimePath.c_str(), file.archs, platform, realerPath);
         const dyld3::MachOAnalyzer* ma = (const dyld3::MachOAnalyzer*)loadedFileInfo.fileContent;
 
         if ( ma != nullptr ) {
-            bool            sipProtected    = false; // isProtectedBySIP(fd);
+            bool            sipProtected    = false;
             bool            issetuid        = false;
             const uint64_t  sliceLen        = loadedFileInfo.sliceLen;
             if ( ma->isDynamicExecutable() ) {
@@ -126,7 +126,9 @@
                 result = true;
         #endif
             }
-            else if ( ma->canBePlacedInDyldCache(runtimePath.c_str(), ^(const char* msg) {}) ) {
+            else if ( ma->canBePlacedInDyldCache(runtimePath.c_str(), ^(const char* msg) {
+                diag.error("Dylib located at '%s' cannot be placed in cache because: '%s'", loadedFileInfo.path, msg);
+            }) ) {
                 file.dylibsForCache.emplace_back(runtimePath, ma, sliceLen, issetuid, sipProtected, loadedFileInfo.sliceOffset, statBuf.st_mtime, statBuf.st_ino);
                 result = true;
            }
@@ -167,7 +169,8 @@
                         return;
                 }
                 // if the file is mach-o, add to list
-                if ( addIfMachO(fileSystem, path, statBuf, files, platform) ) {
+                Diagnostics diag;
+                if ( addIfMachO(fileSystem, path, statBuf, files, platform, diag) ) {
                     if ( multiplePrefixes )
                         alreadyUsed.insert(path);
                 }
@@ -182,7 +185,10 @@
     for (const char* path : sMacOSHostLibs) {
         struct stat statBuf;
         if ( stat(path, &statBuf) == 0 ) {
-            addIfMachO(fileSystem, path, statBuf, allFileSets, dyld3::Platform::macOS);
+            Diagnostics diag;
+            addIfMachO(fileSystem, path, statBuf, allFileSets, dyld3::Platform::macOS, diag);
+            if ( diag.hasError() )
+                fprintf(stderr, "update_dyld_sim_shared_cache: warning: skipping %s because %s\n", path, diag.errorMessage().c_str());
         }
     }
 }
@@ -194,7 +200,10 @@
             std::string fullPath = prefix + path;
             struct stat statBuf;
             if ( stat(fullPath.c_str(), &statBuf) == 0 ) {
-                addIfMachO(fileSystem, path, statBuf, files, dyld3::Platform::macOS);
+                Diagnostics diag;
+                addIfMachO(fileSystem, path, statBuf, files, dyld3::Platform::macOS, diag);
+                if ( diag.hasError() )
+                    fprintf(stderr, "update_dyld_sim_shared_cache: warning: skipping %s because %s\n", fullPath.c_str(), diag.errorMessage().c_str());
             }
         }
     }
@@ -304,6 +313,14 @@
                                         fileSet.otherDylibsAndBundles.end());
 }
 
+
+static std::string getOrderFileContent(const std::string& orderFile)
+{
+    std::ifstream fstream(orderFile);
+    std::stringstream stringBuf;
+    stringBuf << fstream.rdbuf();
+    return stringBuf.str();
+}
 
 static bool existingCacheUpToDate(const std::string& existingCache, const std::vector<DyldSharedCache::MappedMachO>& currentDylibs)
 {
@@ -363,6 +380,26 @@
     return !foundMismatch;
 }
 
+static void addFileSets(const std::unordered_set<std::string>& allowedArchs, std::unordered_set<std::string>& requestedArchs, std::vector<MappedMachOsByCategory>& fileSets)
+{
+    if ( requestedArchs.empty() ) {
+#if __arm64__
+        requestedArchs.insert("arm64");
+#elif __x86_64__
+        requestedArchs.insert("x86_64");
+        requestedArchs.insert("i386");
+#else
+    #error unknown platform
+#endif
+    }
+
+    for (auto& requested : requestedArchs) {
+        if ( allowedArchs.find(requested) != allowedArchs.end() ) {
+            const dyld3::GradedArchs& archs = dyld3::GradedArchs::forName(requested.c_str(), false);
+            fileSets.push_back({archs});
+        }
+    }
+}
 
 inline uint32_t absolutetime_to_milliseconds(uint64_t abstime)
 {
@@ -388,6 +425,7 @@
     std::string                     dirtyDataOrderFile;
     dyld3::Platform                 platform = dyld3::Platform::iOS_simulator;
     std::unordered_set<std::string> skipDylibs;
+    std::unordered_set<std::string> requestedArchs;
     
     // parse command line options
     for (int i = 1; i < argc; ++i) {
@@ -426,6 +464,10 @@
             TERMINATE_IF_LAST_ARG("-dirty_data_order_file missing path argument\n");
             dirtyDataOrderFile = argv[++i];
         }
+        else if (strcmp(arg, "-arch") == 0) {
+            TERMINATE_IF_LAST_ARG("-arch missing arch argument\n");
+            requestedArchs.insert(argv[++i]);
+        }
         else if (strcmp(arg, "-force") == 0) {
             force = true;
         }
@@ -440,11 +482,11 @@
         }
     }
     
-    if ( rootPath.empty()) {
+    if ( rootPath.empty() ) {
         fprintf(stderr, "-root should be specified\n");
         return 1;
     }
-    if (cacheDir.empty()) {
+    if ( cacheDir.empty() ) {
         fprintf(stderr, "-cache_dir should be specified\n");
         return 1;
     }
@@ -452,6 +494,12 @@
     char resolvedPath[PATH_MAX];
     if ( realpath(rootPath.c_str(), resolvedPath) != NULL ) {
         rootPath = resolvedPath;
+    }
+    
+    // canonicalize cacheDir.
+    // Later, path is checked against real path name before writing cache file to avoid TOCTU race condition.
+    if ( realpath(cacheDir.c_str(), resolvedPath) != NULL ) {
+        cacheDir = resolvedPath;
     }
 
     // Find the boot volume so that we can ensure all overlays are on the same volume
@@ -476,23 +524,45 @@
         return 1;
     }
 
+    std::string dylibOrderFileContent;
+    if ( !dylibOrderFile.empty() ) {
+        dylibOrderFileContent = getOrderFileContent(dylibOrderFile);
+    }
+
+    std::string dirtyDataOrderFileContent;
+    if ( !dirtyDataOrderFile.empty() ) {
+        dirtyDataOrderFileContent = getOrderFileContent(dirtyDataOrderFile);
+    }
     uint64_t t1 = mach_absolute_time();
 
     __block std::vector<MappedMachOsByCategory> allFileSets;
+    std::unordered_set<std::string> allowedArchs;
     switch ( platform ) {
         case dyld3::Platform::iOS_simulator:
-            allFileSets.push_back({dyld3::GradedArchs::x86_64});
+            allowedArchs.insert("x86_64");
+            allowedArchs.insert("arm64");
             break;
         case dyld3::Platform::watchOS_simulator:
-            allFileSets.push_back({dyld3::GradedArchs::i386});
+            allowedArchs.insert("i386");
+            allowedArchs.insert("x86_64");
+            allowedArchs.insert("arm64");
+
             break;
         case dyld3::Platform::tvOS_simulator:
-            allFileSets.push_back({dyld3::GradedArchs::x86_64});
+            allowedArchs.insert("x86_64");
+            allowedArchs.insert("arm64");
             break;
         default:
             assert(0 && "invalid platform");
             break;
     }
+
+    addFileSets(allowedArchs, requestedArchs, allFileSets);
+    if ( allFileSets.empty() ) {
+        fprintf(stderr, "update_dyld_sim_shared_cache: error: no valid architecture specified\n");
+        return 1;
+    }
+
     findAllFiles(fileSystem, pathPrefixes, allFileSets, platform);
     addMacOSHostLibs(allFileSets, platform);
     addMacOSBinaries(fileSystem, pathPrefixes, allFileSets);
@@ -526,7 +596,7 @@
         MappedMachOsByCategory& fileSet = allFileSets[index];
         const std::string outFile = cacheDir + "/dyld_sim_shared_cache_" + fileSet.archs.name();
         
-        DyldSharedCache::MappedMachO (^loader)(const std::string&) = ^DyldSharedCache::MappedMachO(const std::string& runtimePath) {
+        DyldSharedCache::MappedMachO (^loader)(const std::string&, Diagnostics&) = ^DyldSharedCache::MappedMachO(const std::string& runtimePath, Diagnostics& diag) {
             if ( skipDylibs.count(runtimePath) )
                 return DyldSharedCache::MappedMachO();
 
@@ -554,7 +624,7 @@
                     
                     std::vector<MappedMachOsByCategory> mappedFiles;
                     mappedFiles.push_back({fileSet.archs});
-                    if ( addIfMachO(fileSystem, runtimePath, statBuf, mappedFiles, platform) ) {
+                    if ( addIfMachO(fileSystem, runtimePath, statBuf, mappedFiles, platform, diag) ) {
                         if ( !mappedFiles.back().dylibsForCache.empty() ) {
                             if ( verbose )
                                 fprintf(stderr, "verifySelfContained, add %s\n", mappedFiles.back().dylibsForCache.back().runtimePath.c_str());
@@ -581,7 +651,7 @@
                 }
             }
             reasons += "\")";
-            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());
+            fprintf(stderr, "update_dyld_sim_shared_cache: warning: %s rejected from cached dylibs: %s (%s)\n", fileSet.archs.name(), exclude.first.runtimePath.c_str(), reasons.c_str());
             fileSet.otherDylibsAndBundles.push_back(exclude.first);
         }
         
@@ -598,9 +668,10 @@
         options.outputMapFilePath            = cacheDir + "/dyld_sim_shared_cache_" + fileSet.archs.name() + ".map";
         options.archs                        = &fileSet.archs;
         options.platform                     = platform;
-        options.excludeLocalSymbols          = false;
+        options.localSymbolMode              = DyldSharedCache::LocalSymbolsMode::keep;
         options.optimizeStubs                = false;
-        options.optimizeObjC                 = true;
+        options.optimizeDyldDlopens          = false;   // don't add dyld3 closures to simulator cache
+        options.optimizeDyldLaunches         = false;   // don't add dyld3 closures to simulator cache
         options.codeSigningDigestMode        = DyldSharedCache::SHA256only;
         options.dylibsRemovedDuringMastering = dylibsRemoved;
         options.inodesAreSameAsRuntime       = true;
@@ -609,8 +680,8 @@
         options.isLocallyBuiltCache          = true;
         options.verbose                      = verbose;
         options.evictLeafDylibsOnOverflow    = true;
-        options.dylibOrdering                = parseOrderFile(dylibOrderFile);
-        options.dirtyDataSegmentOrdering     = parseOrderFile(dirtyDataOrderFile);
+        options.dylibOrdering                = parseOrderFile(dylibOrderFileContent);
+        options.dirtyDataSegmentOrdering     = parseOrderFile(dirtyDataOrderFileContent);
         DyldSharedCache::CreateResults results = DyldSharedCache::create(options, fileSystem, fileSet.dylibsForCache, fileSet.otherDylibsAndBundles, fileSet.mainExecutables);
         
         // print any warnings