1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 * Copyright (c) 2014 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>
41 #include <sys/param.h>
42 #include <sys/sysctl.h>
43 #include <sys/resource.h>
50 #include "mega-dylib-utils.h"
53 This is a compatibility driver to allow us to support migrating to the new cache codebase and format without forcing B&I to alter gencaches.
54 This tool only supports flags used by B&I
55 This intention is for this tool to be removed in the near future and replaced with a tool that is not commandline compatible,
56 but allows shared caches to be built directly out of BuildRecords.
61 [60042] INFO - Executing Command: /SWE/Teams/DT-SWB/iOS/Binaries/Binaries5/update_dyld_shared_cache/update_dyld_shared_cache-357.0.91~2/Root/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/local/bin/update_dyld_shared_cache
63 -root /BuildRoot//Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.Internal.sdk
64 -dylib_list /tmp/dylibs.K93aInternalOS.60042
65 -cache_dir /tmp/K93aInternalOS.60042
68 -dont_map_local_symbols
69 -overlay /SWE/Teams/DT-SWB/iOS/Binaries/Binaries5/XPCService_caches/XPCService_caches-119~94/Root/K93aInternalOS/
70 -overlay /SWE/Teams/DT-SWB/iOS/Binaries/Binaries5/libxpc_caches/libxpc_caches-649~18/Root/K93aInternalOS/
73 // record warnings and add to .map file
74 static std::vector
<std::unique_ptr
<const char>> sWarnings
;
77 static void write_cache(const char* cachePath
, SharedCache
& cache
) {
78 // create temp file for cache
79 int fd
= ::open(cachePath
, O_CREAT
| O_RDWR
| O_TRUNC
, 0644);
81 terminate("can't create temp file %s, errnor=%d", cachePath
, errno
);
83 // try to allocate whole cache file contiguously
84 fstore_t fcntlSpec
= { F_ALLOCATECONTIG
|F_ALLOCATEALL
, F_PEOFPOSMODE
, 0, static_cast<off_t
>(cache
.fileSize()), 0 };
85 ::fcntl(fd
, F_PREALLOCATE
, &fcntlSpec
);
87 // write out cache file
88 if ( ::pwrite(fd
, cache
.buffer().get(), cache
.fileSize(), 0) != cache
.fileSize() )
89 terminate("write() failure creating cache file, errno=%d", errno
);
91 // flush to disk and close
92 int result
= ::fcntl(fd
, F_FULLFSYNC
, NULL
);
94 warning("fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno
, cachePath
);
98 char mapPath
[MAXPATHLEN
];
99 strlcpy(mapPath
, cachePath
, MAXPATHLEN
);
100 strlcat(mapPath
, ".map", MAXPATHLEN
);
101 cache
.writeCacheMapFile(mapPath
);
103 // append any warnings encountered
104 if ( !sWarnings
.empty() ) {
105 FILE* fmap
= ::fopen(mapPath
, "a");
106 if ( fmap
!= NULL
) {
107 fprintf(fmap
, "\n\n");
108 for ( std::unique_ptr
<const char>& msg
: sWarnings
) {
109 fprintf(fmap
, "# %s", &*msg
);
116 int main(int argc
, const char* argv
[])
118 std::set
<ArchPair
> onlyArchs
;
119 const char *rootPath
= NULL
;
120 std::vector
<const char*> searchPaths
;
121 std::vector
<std::unique_ptr
<DylibProxy
>> dylibs
;
122 const char* dylibListFile
= NULL
;
123 // bool force = false;
124 // bool keepSignatures = false;
125 bool explicitCacheDir
= false;
126 bool dontMapLocalSymbols
= false;
127 bool verbose
= false;
128 bool iPhoneOS
= false;
129 const char* cacheDir
= NULL
;
130 const char* archStr
= NULL
;
131 ArchPair
archPair(CPU_TYPE_ARM64
, CPU_SUBTYPE_ARM64_ALL
);
133 // parse command line options
134 for(int i
=1; i
< argc
; ++i
) {
135 const char* arg
= argv
[i
];
136 if ( arg
[0] == '-' ) {
137 if ( strcmp(arg
, "-debug") == 0 ) {
140 else if ( strcmp(arg
, "-dont_map_local_symbols") == 0 ) {
141 dontMapLocalSymbols
= true;
143 else if ( strcmp(arg
, "-iPhone") == 0 ) {
146 else if ( strcmp(arg
, "-dylib_list") == 0 ) {
147 dylibListFile
= argv
[++i
];
148 if ( dylibListFile
== NULL
)
149 terminate("-dylib_list missing path argument\n");
151 else if ( (strcmp(arg
, "-root") == 0) || (strcmp(arg
, "--root") == 0) ) {
152 rootPath
= argv
[++i
];
154 else if ( strcmp(arg
, "-overlay") == 0 ) {
155 const char* path
= argv
[++i
];
157 terminate("-overlay missing path argument\n");
158 searchPaths
.push_back(path
);
160 else if ( strcmp(arg
, "-cache_dir") == 0 ) {
161 cacheDir
= argv
[++i
];
162 if ( cacheDir
== NULL
)
163 terminate("-cache_dir missing path argument\n");
164 explicitCacheDir
= true;
166 else if ( strcmp(arg
, "-arch") == 0 ) {
168 archPair
= archForString(archStr
); // terminates if unknown
170 else if ( strcmp(arg
, "-force") == 0 ) {
171 // ignore. always forced for iOS
175 terminate("unknown option: %s\n", arg
);
180 terminate("unknown option: %s\n", arg
);
185 terminate("-root is a required option\n");
188 terminate("-iPhone is a required option\n");
191 terminate("-cache_dir is a required option\n");
193 if (!dylibListFile
) {
194 terminate("-dylib_list is a required option\n");
197 terminate("-arch is a required option\n");
200 char prodCachePath
[MAXPATHLEN
];
201 char devCachePath
[MAXPATHLEN
];
202 strcpy(prodCachePath
, cacheDir
);
203 if ( prodCachePath
[strlen(prodCachePath
)-1] != '/' )
204 strcat(prodCachePath
, "/");
205 strcat(prodCachePath
, "dyld_shared_cache_");
206 strcat(prodCachePath
, archStr
);
207 strcpy(devCachePath
, prodCachePath
);
208 strcat(devCachePath
, ".development");
210 verboseLog("developement cache path = %s\n", devCachePath
);
211 verboseLog("cache path = %s\n", prodCachePath
);
213 // create cache dirs if needed
214 char neededDirs
[1024];
215 strcpy(neededDirs
, prodCachePath
);
216 char* lastSlash
= strrchr(neededDirs
, '/');
217 if ( lastSlash
!= NULL
)
219 struct stat stat_buf
;
220 if ( stat(neededDirs
, &stat_buf
) != 0 ) {
221 const char* afterSlash
= &neededDirs
[1];
223 while ( (slash
= strchr(afterSlash
, '/')) != NULL
) {
225 ::mkdir(neededDirs
, S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
);
227 afterSlash
= slash
+1;
231 std::string dylibOrderFile
= toolDir() + "/dylib-order.txt";
232 std::string dirtyDataOrderFile
= toolDir() + "/dirty-data-segments-order.txt";
234 std::unordered_map
<std::string
, std::unordered_set
<std::string
>> dependents
;
235 SharedCache
devCache(rootPath
, searchPaths
, dylibListFile
, archPair
, dylibOrderFile
, dirtyDataOrderFile
);
237 if ( devCache
.fileSize() == 0 )
238 terminate("Could not find all necessary dylibs\n");
240 devCache
.buildUnoptimizedCache();
242 SharedCache prodCache
= devCache
;
244 prodCache
.optimizeForProduction();
245 devCache
.optimizeForDevelopment();
247 verboseLog("developement cache size = %llu", devCache
.fileSize());
248 verboseLog("developement cache vm size = %llu", devCache
.vmSize());
251 write_cache(devCachePath
, devCache
);
252 if ( devCache
.vmSize()+align(devCache
.vmSize()/200, sharedRegionRegionAlignment(archPair
)) > sharedRegionRegionSize(archPair
)) {
253 terminate("update_dyld_shared_cache[%u] for arch=%s, shared cache will not fit in shared regions address space. Overflow amount: %llu\n",
254 getpid(), archStr
, devCache
.vmSize()+align(devCache
.vmSize()/200, sharedRegionRegionAlignment(archPair
)) - sharedRegionRegionSize(archPair
));
257 write_cache(prodCachePath
, prodCache
);
263 void uniqueWarning(const char* format
, ...)
266 va_start(list
, format
);
267 vfprintf(stderr
, format
, list
);
269 fprintf(stderr
, "\n");
272 void log(const char * __restrict format
, ...)
275 va_start(list
, format
);
276 vfprintf(stderr
, format
, list
);
278 fprintf(stderr
, "\n");
280 void verboseLog(const char* format
, ...)
283 va_start(list
, format
);
284 vfprintf(stderr
, format
, list
);
286 fprintf(stderr
, "\n");
289 void warning(const char* format
, ...)
291 fprintf(stderr
, "update_dyld_shared_cache warning: ");
293 va_start(list
, format
);
295 vasprintf(&msg
, format
, list
);
297 fprintf(stderr
, "%s\n", msg
);
298 sWarnings
.push_back(std::unique_ptr
<const char>(msg
));
301 void terminate(const char* format
, ...)
303 fprintf(stderr
, "update_dyld_shared_cache error: ");
305 va_start(list
, format
);
306 vfprintf(stderr
, format
, list
);