]> git.saurik.com Git - apple/dyld.git/blob - launch-cache/update_dyld_shared_cache.cpp
dyld-360.21.tar.gz
[apple/dyld.git] / launch-cache / update_dyld_shared_cache.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <mach/mach.h>
29 #include <mach/mach_time.h>
30 #include <limits.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <math.h>
35 #include <fcntl.h>
36 #include <dlfcn.h>
37 #include <signal.h>
38 #include <errno.h>
39 #include <sys/uio.h>
40 #include <unistd.h>
41 #include <dirent.h>
42 #include <sys/param.h>
43 #include <sys/sysctl.h>
44 #include <sys/resource.h>
45 #include <dirent.h>
46 #include <servers/bootstrap.h>
47 #include <mach-o/loader.h>
48 #include <mach-o/fat.h>
49 #include <CoreFoundation/CoreFoundation.h>
50 #include <Security/Security.h>
51 #include <Security/SecCodeSigner.h>
52 #include <CommonCrypto/CommonDigest.h>
53
54 #include "dyld_cache_format.h"
55
56 #include <vector>
57 #include <set>
58 #include <map>
59 #include <unordered_map>
60
61 #include "Architectures.hpp"
62 #include "MachOLayout.hpp"
63 #include "MachORebaser.hpp"
64 #include "MachOBinder.hpp"
65 #include "CacheFileAbstraction.hpp"
66 #include "dyld_cache_config.h"
67
68 #define SELOPT_WRITE
69 #include "objc-shared-cache.h"
70
71 #define FIRST_DYLIB_TEXT_OFFSET 0x10000
72
73 #ifndef LC_FUNCTION_STARTS
74 #define LC_FUNCTION_STARTS 0x26
75 #endif
76
77 static bool verbose = false;
78 static bool progress = false;
79 static bool iPhoneOS = false;
80 static bool rootless = true;
81 static std::vector<const char*> warnings;
82
83
84 static void warn(const char *arch, const char *format, ...)
85 {
86 char *msg;
87
88 va_list args;
89 va_start(args, format);
90 ::vasprintf(&msg, format, args);
91 va_end(args);
92
93 warnings.push_back(msg);
94
95 if ( verbose ) {
96 ::fprintf(::stderr, "update_dyld_shared_cache: warning: %s%s%s%s\n",
97 arch ? "for arch " : "",
98 arch ? arch : "",
99 arch ? ", " : "",
100 msg);
101 }
102 }
103
104
105 class CStringHash {
106 public:
107 size_t operator()(const char* __s) const {
108 size_t __h = 0;
109 for ( ; *__s; ++__s)
110 __h = 5 * __h + *__s;
111 return __h;
112 };
113 };
114 class CStringEquals
115 {
116 public:
117 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
118 };
119
120
121
122 class ArchGraph
123 {
124 public:
125 typedef std::unordered_map<const char*, const char*, CStringHash, CStringEquals> StringToString;
126
127 static void addArchPair(ArchPair ap);
128 static void addRoot(const char* vpath, const std::set<ArchPair>& archs);
129 static uint64_t maxCacheSizeForArchPair(ArchPair ap);
130 static void findSharedDylibs(ArchPair ap);
131 static ArchGraph* graphForArchPair(ArchPair ap) { return fgPerArchGraph[ap]; }
132 static void setFileSystemRoot(const char* root) { fgFileSystemRoot = root; }
133 static void setFileSystemOverlay(const std::vector<const char*>& overlays);
134 static const char* archName(ArchPair ap);
135
136 ArchPair getArchPair() { return fArchPair; }
137 std::set<const class MachOLayoutAbstraction*>& getSharedDylibs() { return fSharedDylibs; }
138 StringToString& getDylibAliases() { return fAliasesMap; }
139 const char* archName() { return archName(fArchPair); }
140
141 private:
142
143 class DependencyNode
144 {
145 public:
146 DependencyNode(ArchGraph*, const char* path, const MachOLayoutAbstraction* layout);
147 void loadDependencies(const MachOLayoutAbstraction*);
148 void markNeededByRoot(DependencyNode*);
149 const char* getPath() const { return fPath; }
150 const MachOLayoutAbstraction* getLayout() const { return fLayout; }
151 size_t useCount() const { return fRootsDependentOnThis.size(); }
152 bool allDependentsFound() const { return !fDependentMissing; }
153 bool dependsOnDylibList() const { return fRootsDependentOnThis.count(const_cast<DependencyNode*>(this)); }
154
155 private:
156 ArchGraph* fGraph;
157 const char* fPath;
158 const MachOLayoutAbstraction* fLayout;
159 bool fDependenciesLoaded;
160 bool fDependentMissing;
161 std::set<DependencyNode*> fDependsOn;
162 std::set<DependencyNode*> fRootsDependentOnThis;
163 };
164
165 typedef std::unordered_map<const char*, class DependencyNode*, CStringHash, CStringEquals> PathToNode;
166
167
168 ArchGraph(ArchPair ap) : fArchPair(ap) {}
169 void addRoot(const char* path, const MachOLayoutAbstraction*);
170 DependencyNode* getNode(const char* path);
171 DependencyNode* getNodeForVirtualPath(const char* vpath);
172 static bool canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap);
173 static bool sharable(const MachOLayoutAbstraction* layout, ArchPair ap, char** msg);
174
175 static std::map<ArchPair, ArchGraph*> fgPerArchGraph;
176 static const char* fgFileSystemRoot;
177 static std::vector<const char*> fgFileSystemOverlays;
178
179 ArchPair fArchPair;
180 std::set<DependencyNode*> fRoots;
181 PathToNode fNodes;
182 std::set<const MachOLayoutAbstraction*> fSharedDylibs; // use set to avoid duplicates when installname!=realpath
183 StringToString fAliasesMap;
184 };
185 std::map<ArchPair, ArchGraph*> ArchGraph::fgPerArchGraph;
186 const char* ArchGraph::fgFileSystemRoot = "";
187 std::vector<const char*> ArchGraph::fgFileSystemOverlays;
188
189 void ArchGraph::addArchPair(ArchPair ap)
190 {
191 //fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
192 fgPerArchGraph[ap] = new ArchGraph(ap);
193 }
194
195 void ArchGraph::setFileSystemOverlay(const std::vector<const char*>& overlays)
196 {
197 for (std::vector<const char*>::const_iterator it=overlays.begin(); it != overlays.end(); ++it)
198 fgFileSystemOverlays.push_back(*it);
199 }
200
201 void ArchGraph::addRoot(const char* vpath, const std::set<ArchPair>& onlyArchs)
202 {
203 //fprintf(stderr, "addRoot(%s)\n", vpath);
204 char completePath[MAXPATHLEN];
205 const char* path = NULL;
206 // check -overlay path first
207 for (std::vector<const char*>::const_iterator it=fgFileSystemOverlays.begin(); it != fgFileSystemOverlays.end(); ++it) {
208 strcpy(completePath, *it);
209 strcat(completePath, vpath); // assumes vpath starts with '/'
210 struct stat stat_buf;
211 if ( stat(completePath, &stat_buf) == 0 ) {
212 path = completePath;
213 break;
214 }
215 }
216 // if not found in overlay, check for -root
217 if ( (path == NULL) && (fgFileSystemRoot[0] != '\0') ) {
218 strcpy(completePath, fgFileSystemRoot);
219 strcat(completePath, vpath); // assumes vpath starts with '/'
220 struct stat stat_buf;
221 if ( stat(completePath, &stat_buf) == 0 )
222 path = completePath;
223 }
224 if ( path == NULL )
225 path = vpath;
226
227 try {
228 //fprintf(stderr, " UniversalMachOLayout::find(%s)\n", path);
229 const UniversalMachOLayout& uni = UniversalMachOLayout::find(path, &onlyArchs);
230 for(std::set<ArchPair>::iterator ait = onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
231 try {
232 const MachOLayoutAbstraction* layout = uni.getSlice(*ait);
233 if ( layout != NULL )
234 fgPerArchGraph[*ait]->addRoot(path, layout);
235 }
236 catch (const char* msg) {
237 if ( verbose )
238 fprintf(stderr, "update_dyld_shared_cache: warning for %s can't use root '%s': %s\n", fgPerArchGraph[*ait]->archName(), path, msg);
239 }
240
241 }
242 }
243 catch (const char* msg) {
244 fprintf(stderr, "update_dyld_shared_cache: warning can't use root '%s': %s\n", path, msg);
245 }
246 }
247
248
249
250 void ArchGraph::addRoot(const char* path, const MachOLayoutAbstraction* layout)
251 {
252 if ( verbose )
253 fprintf(stderr, "update_dyld_shared_cache: adding root: %s\n", path);
254 DependencyNode* node = this->getNode(path);
255 fRoots.insert(node);
256 const MachOLayoutAbstraction* mainExecutableLayout = NULL;
257 if ( layout->getFileType() == MH_EXECUTE )
258 mainExecutableLayout = layout;
259 node->loadDependencies(mainExecutableLayout);
260 node->markNeededByRoot(node);
261 if ( layout->getFileType() == MH_DYLIB )
262 node->markNeededByRoot(NULL);
263 }
264
265 // a virtual path does not have the fgFileSystemRoot prefix
266 ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
267 {
268 //fprintf(stderr, "getNodeForVirtualPath(%s)\n", vpath);
269 char completePath[MAXPATHLEN];
270 for (std::vector<const char*>::const_iterator it=fgFileSystemOverlays.begin(); it != fgFileSystemOverlays.end(); ++it) {
271 const char* overlayPath = *it;
272 // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
273 strcpy(completePath, overlayPath);
274 strcat(completePath, vpath); // assumes vpath starts with '/'
275 struct stat stat_buf;
276 if ( stat(completePath, &stat_buf) == 0 ) {
277 return this->getNode(completePath);
278 }
279 // <rdar://problem/9279770> support when install name is a symlink
280 const char* pathToSymlink = vpath;
281 if ( fgFileSystemRoot[0] != '\0' ) {
282 strcpy(completePath, fgFileSystemRoot);
283 strcat(completePath, vpath);
284 pathToSymlink = completePath;
285 }
286 if ( (lstat(pathToSymlink, &stat_buf) == 0) && S_ISLNK(stat_buf.st_mode) ) {
287 // requested path did not exist in /overlay, but leaf of path is a symlink in /
288 char pathInSymLink[MAXPATHLEN];
289 size_t res = readlink(pathToSymlink, pathInSymLink, sizeof(pathInSymLink));
290 if ( res != -1 ) {
291 pathInSymLink[res] = '\0';
292 if ( pathInSymLink[0] != '/' ) {
293 char symFullPath[MAXPATHLEN];
294 strcpy(symFullPath, vpath);
295 char* lastSlash = strrchr(symFullPath, '/');
296 if ( lastSlash != NULL ) {
297 strcpy(lastSlash+1, pathInSymLink);
298 // (re)try looking for what symlink points to, but in /overlay
299 return this->getNodeForVirtualPath(symFullPath);
300 }
301 }
302 }
303 }
304 }
305
306 if ( fgFileSystemRoot[0] != '\0' ) {
307 // using -root means always use /rootpath/usr/lib
308 strcpy(completePath, fgFileSystemRoot);
309 strcat(completePath, vpath); // assumes vpath starts with '/'
310 return this->getNode(completePath);
311 }
312 // not found in -overlay or -root not used
313 return this->getNode(vpath);
314 }
315
316 ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
317 {
318 //fprintf(stderr, "getNode(%s)\n", path);
319 // look up supplied path to see if node already exists
320 PathToNode::iterator pos = fNodes.find(path);
321 if ( pos != fNodes.end() )
322 return pos->second;
323
324 // get real path
325 char realPath[MAXPATHLEN];
326 if ( realpath(path, realPath) == NULL )
327 throwf("realpath() failed on %s\n", path);
328
329 // look up real path to see if node already exists
330 pos = fNodes.find(realPath);
331 if ( pos != fNodes.end() ) {
332 // update fAliasesMap with symlinks found
333 const char* aliasPath = path;
334 if ( (fgFileSystemRoot != NULL) && (strncmp(path, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
335 aliasPath = &path[strlen(fgFileSystemRoot)];
336 }
337 if ( fAliasesMap.find(aliasPath) == fAliasesMap.end() ) {
338 if ( strcmp(aliasPath, pos->second->getLayout()->getID().name) != 0 ) {
339 fAliasesMap[strdup(aliasPath)] = pos->second->getLayout()->getID().name;
340 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
341 }
342 }
343 return pos->second;
344 }
345
346 // still does not exist, so create a new node
347 const UniversalMachOLayout& uni = UniversalMachOLayout::find(realPath);
348 DependencyNode* node = new DependencyNode(this, realPath, uni.getSlice(fArchPair));
349 if ( node->getLayout() == NULL ) {
350 throwf("%s is missing arch %s", realPath, archName(fArchPair));
351 }
352 // add realpath to node map
353 fNodes[node->getPath()] = node;
354 // if install name is not real path, add install name to node map
355 if ( (node->getLayout()->getFileType() == MH_DYLIB) && (strcmp(realPath, node->getLayout()->getID().name) != 0) ) {
356 //fprintf(stderr, "adding %s node alias %s for %s\n", archName(fArchPair), node->getLayout()->getID().name, realPath);
357 pos = fNodes.find(node->getLayout()->getID().name);
358 if ( pos != fNodes.end() ) {
359 // get uuids of two dylibs to see if this is accidental copy of a dylib or two differnent dylibs with same -install_name
360 uuid_t uuid1;
361 uuid_t uuid2;
362 node->getLayout()->uuid(uuid1);
363 pos->second->getLayout()->uuid(uuid2);
364 if ( memcmp(&uuid1, &uuid2, 16) == 0 ) {
365 // <rdar://problem/8305479> warn if two dylib in cache have same install_name
366 char* msg;
367 asprintf(&msg, "update_dyld_shared_cache: warning, found two copies of the same dylib with same install path: %s\n\t%s\n\t%s\n",
368 node->getLayout()->getID().name, pos->second->getPath(), node->getPath());
369 fprintf(stderr, "%s", msg);
370 warnings.push_back(msg);
371 }
372 else {
373 // <rdar://problem/12763450> update_dyld_shared_cache should fail if two images have same install name
374 fprintf(stderr, "update_dyld_shared_cache: found two different dylibs with same install path: %s\n\t%s\n\t%s\n",
375 node->getLayout()->getID().name, pos->second->getPath(), node->getPath());
376 exit(1);
377 }
378 }
379 else
380 fNodes[node->getLayout()->getID().name] = node;
381 // update fAliasesMap with symlinks found
382 const char* aliasPath = realPath;
383 if ( (fgFileSystemRoot != NULL) && (fgFileSystemRoot[0] != '\0') && (strncmp(realPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
384 aliasPath = &realPath[strlen(fgFileSystemRoot)];
385 }
386 // <rdar://problem/11192810> Too many aliases in -overlay mode
387 for (std::vector<const char*>::const_iterator it=fgFileSystemOverlays.begin(); it != fgFileSystemOverlays.end(); ++it) {
388 const char* overlayPath = *it;
389 if ( strncmp(realPath, overlayPath, strlen(overlayPath)) == 0 ) {
390 aliasPath = &realPath[strlen(overlayPath)];
391 break;
392 }
393 }
394 if ( fAliasesMap.find(aliasPath) == fAliasesMap.end() ) {
395 if ( strcmp(aliasPath, node->getLayout()->getID().name) != 0 ) {
396 fAliasesMap[strdup(aliasPath)] = node->getLayout()->getID().name;
397 //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
398 }
399 }
400 }
401 return node;
402 }
403
404
405 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction* mainExecutableLayout)
406 {
407 if ( !fDependenciesLoaded ) {
408 fDependenciesLoaded = true;
409 // add dependencies
410 const std::vector<MachOLayoutAbstraction::Library>& dependsOn = fLayout->getLibraries();
411 for(std::vector<MachOLayoutAbstraction::Library>::const_iterator it = dependsOn.begin(); it != dependsOn.end(); ++it) {
412 try {
413 const char* dependentPath = it->name;
414 if ( strncmp(dependentPath, "@executable_path/", 17) == 0 ) {
415 if ( mainExecutableLayout == NULL )
416 throw "@executable_path without main executable";
417 // expand @executable_path path prefix
418 const char* executablePath = mainExecutableLayout->getFilePath();
419 char newPath[strlen(executablePath) + strlen(dependentPath)+2];
420 if ( (fgFileSystemRoot != NULL) && (strncmp(executablePath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
421 // executablePath already has rootPath prefix, need to remove that to get to base virtual path
422 strcpy(newPath, &executablePath[strlen(fgFileSystemRoot)]);
423 }
424 else {
425 strcpy(newPath, executablePath);
426 }
427 char* addPoint = strrchr(newPath,'/');
428 if ( addPoint != NULL )
429 strcpy(&addPoint[1], &dependentPath[17]);
430 else
431 strcpy(newPath, &dependentPath[17]);
432 dependentPath = strdup(newPath);
433 }
434 else if ( strncmp(dependentPath, "@loader_path/", 13) == 0 ) {
435 // expand @loader_path path prefix
436 char newPath[strlen(fPath) + strlen(dependentPath)+2];
437 if ( (fgFileSystemRoot != NULL) && (strncmp(fPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
438 // fPath already has rootPath prefix, need to remove that to get to base virtual path
439 strcpy(newPath, &fPath[strlen(fgFileSystemRoot)]);
440 }
441 else {
442 strcpy(newPath, fPath);
443 }
444 char* addPoint = strrchr(newPath,'/');
445 if ( addPoint != NULL )
446 strcpy(&addPoint[1], &dependentPath[13]);
447 else
448 strcpy(newPath, &dependentPath[13]);
449 dependentPath = strdup(newPath);
450 }
451 else if ( strncmp(dependentPath, "@rpath/", 7) == 0 ) {
452 throw "@rpath not supported in dyld shared cache";
453 }
454 // <rdar://problem/9161945> silently ignore dependents from main executables that can't be in shared cache
455 bool addDependent = true;
456 if ( fLayout->getFileType() == MH_EXECUTE ) {
457 if ( (strncmp(dependentPath, "/usr/lib/", 9) != 0) && (strncmp(dependentPath, "/System/Library/", 16) != 0) ) {
458 addDependent = false;
459 }
460 }
461 if ( addDependent )
462 fDependsOn.insert(fGraph->getNodeForVirtualPath(dependentPath));
463 }
464 catch (const char* msg) {
465 if ( it->weakImport || ! fLayout->hasSplitSegInfo() ) {
466 // ok to ignore missing weak imported dylibs from things that are
467 // not going to be in the dyld shared cache
468 }
469 else {
470 fprintf(stderr, "warning, could not bind %s because %s\n", fPath, msg);
471 fDependentMissing = true;
472 }
473 }
474 }
475 // recurse
476 for(std::set<DependencyNode*>::iterator it = fDependsOn.begin(); it != fDependsOn.end(); ++it) {
477 (*it)->loadDependencies(mainExecutableLayout);
478 }
479 }
480 }
481
482 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode* rootNode)
483 {
484 if ( fRootsDependentOnThis.count(rootNode) == 0 ) {
485 fRootsDependentOnThis.insert(rootNode);
486 for(std::set<DependencyNode*>::iterator it = fDependsOn.begin(); it != fDependsOn.end(); ++it) {
487 (*it)->markNeededByRoot(rootNode);
488 }
489 }
490 }
491
492
493
494 ArchGraph::DependencyNode::DependencyNode(ArchGraph* graph, const char* path, const MachOLayoutAbstraction* layout)
495 : fGraph(graph), fPath(strdup(path)), fLayout(layout), fDependenciesLoaded(false), fDependentMissing(false)
496 {
497 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
498 }
499
500 uint64_t ArchGraph::maxCacheSizeForArchPair(ArchPair ap) {
501 switch ( ap.arch ) {
502 case CPU_TYPE_I386:
503 return 0x20000000;
504 case CPU_TYPE_X86_64:
505 return 0x40000000;
506 case CPU_TYPE_ARM:
507 return ARM_SHARED_REGION_SIZE;
508 case CPU_TYPE_ARM64:
509 return ARM64_SHARED_REGION_SIZE;
510 default: return UINT64_MAX;
511 }
512 }
513
514 void ArchGraph::findSharedDylibs(ArchPair ap)
515 {
516 const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
517 std::set<const MachOLayoutAbstraction*> possibleLibs;
518 std::map<const MachOLayoutAbstraction*, const DependencyNode *> layoutToNode;
519 //fprintf(stderr, "shared for arch %s\n", archName(ap));
520 for(PathToNode::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
521 DependencyNode* node = it->second;
522 // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
523 if ( node->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
524 const MachOLayoutAbstraction* layout = node->getLayout();
525 if ( layout->isDylib() ) {
526 char* msg;
527 if ( sharable(layout, ap, &msg) ) {
528 possibleLibs.insert(layout);
529 layoutToNode[layout] = node;
530 }
531 else {
532 if ( !iPhoneOS && (layout->getID().name[0] == '@') ) {
533 // <rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
534 }
535 else {
536 warnings.push_back(msg);
537 fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
538 }
539 }
540 }
541 }
542 }
543
544 // prune so that all shareable libs depend only on other shareable libs
545 std::set<const MachOLayoutAbstraction*>& sharedLibs = fgPerArchGraph[ap]->fSharedDylibs;
546 std::map<const MachOLayoutAbstraction*,bool> shareableMap;
547 uint64_t totalLibSize = 0;
548 for (std::set<const MachOLayoutAbstraction*>::iterator lit = possibleLibs.begin(); lit != possibleLibs.end(); ++lit) {
549 if ( canBeShared(*lit, ap, possibleLibs, shareableMap) ) {
550 totalLibSize += (*lit)->getVMSize();
551 sharedLibs.insert(*lit);
552 }
553 }
554
555 #if 0 // disable auto-eviction because it happens before linkedit optimization which means it is overly conservative.
556
557 // Check to see if the unoptimized cache size is too large, if so trim out some libraries
558 uint64_t maxCacheSize = maxCacheSizeForArchPair(ap);
559 if (totalLibSize > maxCacheSize) {
560 fprintf(stderr, "update_dyld_shared_cache: unoptimized %s shared cache overflow, total VM space: %lldMB (max=%lldMB)\n", archName(ap), totalLibSize/(1024*1024), maxCacheSize/(1024*1024));
561 std::vector<const MachOLayoutAbstraction*> removableLibs;
562
563 for (const MachOLayoutAbstraction* layout : sharedLibs) {
564 // Every library uses itself, and every MH_DYLIB has an extra useCount, so we know useCount of 2 implies nothing else in the shared cache uses it
565 if (layoutToNode[layout]->useCount() == 2) {
566 if ( layoutToNode[layout]->dependsOnDylibList() ) {
567 removableLibs.push_back(layout);
568 //fprintf(stderr, " possible to evict: %s\n", layout->getID().name);
569 }
570 }
571 }
572
573 std::sort(removableLibs.begin(), removableLibs.end(), [](const MachOLayoutAbstraction* a, const MachOLayoutAbstraction* b){
574 return a->getVMSize() < b->getVMSize();
575 });
576
577 while ( (totalLibSize > maxCacheSize) && !removableLibs.empty() ) {
578 const MachOLayoutAbstraction* largestRemovableLib = removableLibs.back();
579 removableLibs.pop_back();
580 if ( largestRemovableLib->getVMSize() > 1024*1024 )
581 fprintf(stderr, "update_dyld_shared_cache: evicting % 3lldMB leaf dylib %s\n", largestRemovableLib->getVMSize()/(1024*1024), largestRemovableLib->getID().name);
582 else
583 fprintf(stderr, "update_dyld_shared_cache: evicting % 3lldKB leaf dylib %s\n", largestRemovableLib->getVMSize()/1024, largestRemovableLib->getID().name);
584 sharedLibs.erase(largestRemovableLib);
585 totalLibSize -= largestRemovableLib->getVMSize();
586 }
587 fprintf(stderr, "update_dyld_shared_cache: unoptimized %s shared cache reduced to total VM space: %lldMB\n", archName(ap), totalLibSize/1024/1024);
588 }
589 #endif
590 }
591
592 const char* ArchGraph::archName(ArchPair ap)
593 {
594 switch ( ap.arch ) {
595 case CPU_TYPE_I386:
596 return "i386";
597 case CPU_TYPE_X86_64:
598 switch ( ap.subtype ) {
599 case CPU_SUBTYPE_X86_64_H:
600 return "x86_64h";
601 default:
602 return "x86_64";
603 }
604 case CPU_TYPE_ARM:
605 switch ( ap.subtype ) {
606 case CPU_SUBTYPE_ARM_V4T:
607 return "armv4t";
608 case CPU_SUBTYPE_ARM_V6:
609 return "armv6";
610 case CPU_SUBTYPE_ARM_V5TEJ:
611 return "armv5";
612 case CPU_SUBTYPE_ARM_XSCALE:
613 return "arm-xscale";
614 case CPU_SUBTYPE_ARM_V7:
615 return "armv7";
616 case CPU_SUBTYPE_ARM_V7F:
617 return "armv7f";
618 case CPU_SUBTYPE_ARM_V7K:
619 return "armv7k";
620 case CPU_SUBTYPE_ARM_V7S:
621 return "armv7s";
622 default:
623 return "arm";
624 }
625 case CPU_TYPE_ARM64:
626 return "arm64";
627 default:
628 return "unknown";
629 }
630 }
631
632 bool ArchGraph::sharable(const MachOLayoutAbstraction* layout, ArchPair ap, char** msg)
633 {
634 int trustErr = layout->notTrusted();
635 if ( ! layout->isTwoLevelNamespace() )
636 asprintf(msg, "can't put %s in shared cache because it was built -flat_namespace", layout->getID().name);
637 else if ( ! layout->inSharableLocation() )
638 asprintf(msg, "can't put %s in shared cache because its -install_name is not in /usr/lib or /System/Library", layout->getID().name);
639 else if ( ! layout->hasSplitSegInfo() )
640 asprintf(msg, "can't put %s in shared cache because it was not built for %s or later", layout->getID().name, (iPhoneOS ? "iPhoneOS 3.1" : "MacOSX 10.5"));
641 else if ( rootless == true && trustErr != 0 )
642 asprintf(msg, "can't put %s in shared cache because it is not trusted: %s", layout->getFilePath(), strerror(trustErr));
643 else if ( layout->hasDynamicLookupLinkage() )
644 asprintf(msg, "can't put %s in shared cache because it was built with '-undefined dynamic_lookup'", layout->getID().name);
645 else if ( layout->hasMainExecutableLookupLinkage() )
646 asprintf(msg, "can't put %s in shared cache because it was built with '-bundle_loader'", layout->getID().name);
647 else
648 return true;
649 return false;
650 }
651
652 bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap)
653 {
654 // check map which is a cache of results
655 std::map<const MachOLayoutAbstraction*, bool>::iterator mapPos = shareableMap.find(layout);
656 if ( mapPos != shareableMap.end() ) {
657 return mapPos->second;
658 }
659 // see if possible
660 if ( possibleLibs.count(layout) == 0 ) {
661 shareableMap[layout] = false;
662 char* msg;
663 if ( sharable(layout, ap, &msg) )
664 asprintf(&msg, "can't put %s in shared cache, unknown reason", layout->getID().name);
665 warnings.push_back(msg);
666 if ( verbose )
667 fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
668 return false;
669 }
670 // look recursively
671 shareableMap[layout] = true; // mark this shareable early in case of circular references
672 const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
673 const std::vector<MachOLayoutAbstraction::Library>& dependents = layout->getLibraries();
674 for (std::vector<MachOLayoutAbstraction::Library>::const_iterator dit = dependents.begin(); dit != dependents.end(); ++dit) {
675 PathToNode::const_iterator pos = nodes.find(dit->name);
676 if ( pos == nodes.end() ) {
677 // path from load command does not match any loaded dylibs, maybe there is a temp symlink
678 char realPath[MAXPATHLEN];
679 if ( realpath(dit->name, realPath) != NULL ) {
680 if ( nodes.find(realPath) != nodes.end() )
681 continue;
682 }
683 // handle weak imported dylibs not found
684 if ( dit->weakImport )
685 continue;
686 shareableMap[layout] = false;
687 char* msg;
688 asprintf(&msg, "can't put %s in shared cache because it depends on %s which can't be found", layout->getID().name, dit->name);
689 warnings.push_back(msg);
690 if ( verbose )
691 fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
692 return false;
693 }
694 else {
695 if ( ! canBeShared(pos->second->getLayout(), ap, possibleLibs, shareableMap) ) {
696 shareableMap[layout] = false;
697 char* msg;
698 asprintf(&msg, "can't put %s in shared cache because it depends on %s which can't be in shared cache", layout->getID().name, dit->name);
699 warnings.push_back(msg);
700 if ( verbose )
701 fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
702 return false;
703 }
704 }
705 }
706 return true;
707 }
708
709
710
711 class StringPool
712 {
713 public:
714 StringPool();
715 const char* getBuffer();
716 uint32_t size();
717 uint32_t add(const char* str);
718 uint32_t addUnique(const char* str);
719 const char* stringAtIndex(uint32_t) const;
720
721 private:
722 typedef std::unordered_map<const char*, uint32_t, CStringHash, CStringEquals> StringToOffset;
723
724 char* fBuffer;
725 uint32_t fBufferAllocated;
726 uint32_t fBufferUsed;
727 StringToOffset fUniqueStrings;
728 };
729
730
731 StringPool::StringPool()
732 : fBufferUsed(0), fBufferAllocated(128*1024*1024)
733 {
734 fBuffer = (char*)malloc(fBufferAllocated);
735 }
736
737 uint32_t StringPool::add(const char* str)
738 {
739 uint32_t len = strlen(str);
740 if ( (fBufferUsed + len + 1) > fBufferAllocated ) {
741 // grow buffer
742 throw "string buffer exhausted";
743 }
744 strcpy(&fBuffer[fBufferUsed], str);
745 uint32_t result = fBufferUsed;
746 fUniqueStrings[&fBuffer[fBufferUsed]] = result;
747 fBufferUsed += len+1;
748 return result;
749 }
750
751 uint32_t StringPool::addUnique(const char* str)
752 {
753 StringToOffset::iterator pos = fUniqueStrings.find(str);
754 if ( pos != fUniqueStrings.end() )
755 return pos->second;
756 else {
757 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
758 return this->add(str);
759 }
760 }
761
762 uint32_t StringPool::size()
763 {
764 return fBufferUsed;
765 }
766
767 const char* StringPool::getBuffer()
768 {
769 return fBuffer;
770 }
771
772 const char* StringPool::stringAtIndex(uint32_t index) const
773 {
774 return &fBuffer[index];
775 }
776
777
778
779 struct LocalSymbolInfo
780 {
781 uint32_t dylibOffset;
782 uint32_t nlistStartIndex;
783 uint32_t nlistCount;
784 };
785
786
787 template <typename A>
788 class SharedCache
789 {
790 public:
791 SharedCache(ArchGraph* graph, const char* rootPath, const std::vector<const char*>& overlayPaths, const char* cacheDir, bool explicitCacheDir,
792 bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress);
793 bool update(bool force, bool optimize, bool deleteExistingFirst, int archIndex,
794 int archCount, bool keepSignatures, bool dontMapLocalSymbols);
795 void writeCacheFile(const char *cacheFilePath, uint8_t *cacheFileBuffer, uint32_t cacheFileSize, bool deleteOldCache);
796 static const char* cacheFileSuffix(bool optimized, const char* archName);
797
798 // vm address = address AS WRITTEN into the cache
799 // mapped address = address AS MAPPED into the update process only
800 // file offset = offset relative to start of cache file
801 void * mappedAddressForVMAddress(uint64_t vmaddr);
802 uint64_t VMAddressForMappedAddress(const void *mapaddr);
803 uint64_t cacheFileOffsetForVMAddress(uint64_t addr) const;
804 uint64_t VMAddressForCacheFileOffset(uint64_t addr) const;
805
806 static const char* archName();
807
808 private:
809 typedef typename A::P P;
810 typedef typename A::P::E E;
811 typedef typename A::P::uint_t pint_t;
812
813 bool notUpToDate(const char* path, unsigned int aliasCount);
814 bool notUpToDate(const void* cache, unsigned int aliasCount);
815 uint8_t* optimizeLINKEDIT(bool keepSignatures, bool dontMapLocalSymbols);
816 void optimizeObjC(std::vector<void*>& pointersInData);
817
818 static void getSharedCacheBasAddresses(cpu_type_t arch, uint64_t* baseReadOnly, uint64_t* baseWritable);
819 static cpu_type_t arch();
820 static uint64_t sharedRegionStartAddress();
821 static uint64_t sharedRegionSize();
822 static uint64_t sharedRegionStartWritableAddress(uint64_t);
823 static uint64_t sharedRegionStartReadOnlyAddress(uint64_t, uint64_t);
824 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide);
825 static bool addCacheSlideInfo();
826 static uint64_t pathHash(const char*);
827
828 static uint64_t pageAlign(uint64_t addr);
829 static uint64_t regionAlign(uint64_t addr);
830 static uint64_t pageAlign4KB(uint64_t addr);
831 void assignNewBaseAddresses(bool verify);
832
833 struct LayoutInfo {
834 const MachOLayoutAbstraction* layout;
835 std::vector<const char*> aliases;
836 dyld_cache_image_info info;
837 };
838
839 struct ByNameSorter {
840 bool operator()(const LayoutInfo& left, const LayoutInfo& right)
841 { return (strcmp(left.layout->getID().name, right.layout->getID().name) < 0); }
842 };
843
844 struct ByAddressSorter {
845 bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
846 return (left.layout->getSegments()[0].newAddress() < right.layout->getSegments()[0].newAddress());
847 }
848 };
849
850 struct ByCStringSectionSizeSorter {
851 bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
852 const std::vector<MachOLayoutAbstraction::Segment>& segs_l =
853 left.layout->getSegments();
854 const std::vector<MachOLayoutAbstraction::Segment>& segs_r =
855 right.layout->getSegments();
856 if (segs_l.size() == 0 || segs_r.size() == 0) {
857 // one image has no segments
858 return segs_l.size() > segs_r.size();
859 }
860 const macho_header<P> *mh_l = (macho_header<P>*)segs_l[0].mappedAddress();
861 const macho_header<P> *mh_r = (macho_header<P>*)segs_r[0].mappedAddress();
862 const macho_section<P> *cstring_l = mh_l->getSection("__TEXT", "__cstring");
863 const macho_section<P> *cstring_r = mh_r->getSection("__TEXT", "__cstring");
864 if (!cstring_l || !cstring_r) {
865 // one image has no cstrings
866 return cstring_l && !cstring_r;
867 }
868
869 return cstring_l->size() > cstring_r->size();
870 }
871 };
872
873 struct Sorter {
874 Sorter(std::map<const MachOLayoutAbstraction*, uint32_t>& map): fMap(map) {}
875 bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
876 return (fMap[left.layout] < fMap[right.layout]);
877 }
878 private:
879 std::map<const MachOLayoutAbstraction*, uint32_t>& fMap;
880 };
881
882
883 ArchGraph* fArchGraph;
884 const bool fVerify;
885 bool fExistingIsNotUpToDate;
886 bool fCacheFileInFinalLocation;
887 const char* fCacheFilePath;
888 uint8_t* fExistingCacheForVerification;
889 std::vector<LayoutInfo> fDylibs;
890 std::vector<LayoutInfo> fDylibAliases;
891 std::vector<shared_file_mapping_np> fMappings;
892 std::vector<macho_nlist<P> > fUnmappedLocalSymbols;
893 StringPool fUnmappedLocalsStringPool;
894 std::vector<LocalSymbolInfo> fLocalSymbolInfos;
895 uint32_t fHeaderSize;
896 uint8_t* fInMemoryCache;
897 uint64_t fDyldBaseAddress;
898 uint64_t fLinkEditsTotalUnoptimizedSize;
899 uint64_t fLinkEditsStartAddress;
900 MachOLayoutAbstraction::Segment* fFirstLinkEditSegment;
901 uint32_t fOffsetOfBindInfoInCombinedLinkedit;
902 uint32_t fOffsetOfWeakBindInfoInCombinedLinkedit;
903 uint32_t fOffsetOfLazyBindInfoInCombinedLinkedit;
904 uint32_t fOffsetOfExportInfoInCombinedLinkedit;
905 uint32_t fOffsetOfOldSymbolTableInfoInCombinedLinkedit;
906 uint32_t fSizeOfOldSymbolTableInfoInCombinedLinkedit;
907 uint32_t fOffsetOfOldExternalRelocationsInCombinedLinkedit;
908 uint32_t fSizeOfOldExternalRelocationsInCombinedLinkedit;
909 uint32_t fOffsetOfOldIndirectSymbolsInCombinedLinkedit;
910 uint32_t fSizeOfOldIndirectSymbolsInCombinedLinkedit;
911 uint32_t fOffsetOfOldStringPoolInCombinedLinkedit;
912 uint32_t fSizeOfOldStringPoolInCombinedLinkedit;
913 uint32_t fOffsetOfFunctionStartsInCombinedLinkedit;
914 uint32_t fSizeOfFunctionStartsInCombinedLinkedit;
915 uint32_t fOffsetOfDataInCodeInCombinedLinkedit;
916 uint32_t fSizeOfDataInCodeInCombinedLinkedit;
917 uint32_t fLinkEditsTotalOptimizedSize;
918 uint32_t fUnmappedLocalSymbolsSize;
919 };
920
921
922 // Access a section containing a list of pointers
923 template <typename A, typename T>
924 class PointerSection
925 {
926 typedef typename A::P P;
927 typedef typename A::P::uint_t pint_t;
928
929 SharedCache<A>* const fCache;
930 const macho_section<P>* const fSection;
931 pint_t * const fBase;
932 pint_t fCount;
933
934 public:
935 PointerSection(SharedCache<A>* cache, const macho_header<P>* header,
936 const char *segname, const char *sectname)
937 : fCache(cache)
938 , fSection(header->getSection(segname, sectname))
939 , fBase(fSection ? (pint_t *)cache->mappedAddressForVMAddress(fSection->addr()) : 0)
940 , fCount(fSection ? fSection->size() / sizeof(pint_t) : 0)
941 {
942 }
943
944 pint_t count() const { return fCount; }
945
946 pint_t getVMAddress(pint_t index) const {
947 if (index >= fCount) throwf("index out of range");
948 return P::getP(fBase[index]);
949 }
950
951 T get(pint_t index) const {
952 return (T)fCache->mappedAddressForVMAddress(getVMAddress(index));
953 }
954
955 void setVMAddress(pint_t index, pint_t value) {
956 if (index >= fCount) throwf("index out of range");
957 P::setP(fBase[index], value);
958 }
959
960 void removeNulls() {
961 pint_t shift = 0;
962 for (pint_t i = 0; i < fCount; i++) {
963 pint_t value = fBase[i];
964 if (value) {
965 fBase[i-shift] = value;
966 } else {
967 shift++;
968 }
969 }
970 fCount -= shift;
971 const_cast<macho_section<P>*>(fSection)->set_size(fCount * sizeof(pint_t));
972 }
973 };
974
975 // Access a section containing an array of structures
976 template <typename A, typename T>
977 class ArraySection
978 {
979 typedef typename A::P P;
980
981 SharedCache<A>* const fCache;
982 const macho_section<P>* const fSection;
983 T * const fBase;
984 uint64_t const fCount;
985
986 public:
987 ArraySection(SharedCache<A>* cache, const macho_header<P>* header,
988 const char *segname, const char *sectname)
989 : fCache(cache)
990 , fSection(header->getSection(segname, sectname))
991 , fBase(fSection ? (T *)cache->mappedAddressForVMAddress(fSection->addr()) : 0)
992 , fCount(fSection ? fSection->size() / sizeof(T) : 0)
993 {
994 }
995
996 uint64_t count() const { return fCount; }
997
998 T& get(uint64_t index) const {
999 if (index >= fCount) throwf("index out of range");
1000 return fBase[index];
1001 }
1002 };
1003
1004
1005 // GrP fixme
1006 #include "ObjCLegacyAbstraction.hpp"
1007 #include "ObjCModernAbstraction.hpp"
1008
1009
1010
1011 template <> cpu_type_t SharedCache<x86>::arch() { return CPU_TYPE_I386; }
1012 template <> cpu_type_t SharedCache<x86_64>::arch() { return CPU_TYPE_X86_64; }
1013 template <> cpu_type_t SharedCache<arm>::arch() { return CPU_TYPE_ARM; }
1014 template <> cpu_type_t SharedCache<arm64>::arch() { return CPU_TYPE_ARM64; }
1015
1016 template <> uint64_t SharedCache<x86>::sharedRegionStartAddress() { return 0x90000000; }
1017 template <> uint64_t SharedCache<x86_64>::sharedRegionStartAddress() { return 0x7FFF80000000LL; }
1018 template <> uint64_t SharedCache<arm>::sharedRegionStartAddress() { return ARM_SHARED_REGION_START; }
1019 template <> uint64_t SharedCache<arm64>::sharedRegionStartAddress() { return ARM64_SHARED_REGION_START; }
1020
1021 template <> uint64_t SharedCache<x86>::sharedRegionSize() { return 0x20000000; }
1022 template <> uint64_t SharedCache<x86_64>::sharedRegionSize() { return 0x40000000; }
1023 template <> uint64_t SharedCache<arm>::sharedRegionSize() { return ARM_SHARED_REGION_SIZE; }
1024 template <> uint64_t SharedCache<arm64>::sharedRegionSize() { return ARM64_SHARED_REGION_SIZE; }
1025
1026 template <> uint64_t SharedCache<x86>::sharedRegionStartWritableAddress(uint64_t exEnd) { return exEnd + 0x04000000; }
1027 template <> uint64_t SharedCache<x86_64>::sharedRegionStartWritableAddress(uint64_t exEnd) { return 0x7FFF70000000LL; }
1028 template <> uint64_t SharedCache<arm>::sharedRegionStartWritableAddress(uint64_t exEnd) { return (exEnd + 16383) & (-16384); }
1029 template <> uint64_t SharedCache<arm64>::sharedRegionStartWritableAddress(uint64_t exEnd) { return exEnd; }
1030
1031 template <> uint64_t SharedCache<x86>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd) { return wrEnd + 0x04000000; }
1032 template <> uint64_t SharedCache<x86_64>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd){ return exEnd; }
1033 template <> uint64_t SharedCache<arm>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd) { return (wrEnd + 16383) & (-16384); }
1034 template <> uint64_t SharedCache<arm64>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd) { return (wrEnd + 16383) & (-16384); }
1035
1036 template <> const char* SharedCache<x86>::archName() { return "i386"; }
1037 template <> const char* SharedCache<x86_64>::archName() { return "x86_64"; }
1038 template <> const char* SharedCache<arm>::archName() { return "arm"; }
1039 template <> const char* SharedCache<arm64>::archName() { return "arm64"; }
1040
1041 template <> const char* SharedCache<x86>::cacheFileSuffix(bool, const char* archName) { return archName; }
1042 template <> const char* SharedCache<x86_64>::cacheFileSuffix(bool, const char* archName){ return archName; }
1043 template <> const char* SharedCache<arm>::cacheFileSuffix(bool, const char* archName) { return archName; }
1044 template <> const char* SharedCache<arm64>::cacheFileSuffix(bool, const char* archName) { return archName; }
1045
1046 template <> uint64_t SharedCache<x86>::pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
1047 template <> uint64_t SharedCache<x86_64>::pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
1048 template <> uint64_t SharedCache<arm>::pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
1049 template <> uint64_t SharedCache<arm64>::pageAlign(uint64_t addr) { return ( (addr + 16383) & (-16384) ); }
1050
1051 template <> uint64_t SharedCache<x86>::regionAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
1052 template <> uint64_t SharedCache<x86_64>::regionAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
1053 template <> uint64_t SharedCache<arm>::regionAlign(uint64_t addr) { return ( (addr + 16383) & (-16384) ); }
1054 template <> uint64_t SharedCache<arm64>::regionAlign(uint64_t addr) { return ( (addr + 16383) & (-16384) ); }
1055
1056
1057 template <typename A>
1058 uint64_t SharedCache<A>::pageAlign4KB(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
1059
1060 template <typename A>
1061 SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const std::vector<const char*>& overlayPaths, const char* cacheDir, bool explicitCacheDir, bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress)
1062 : fArchGraph(graph), fVerify(verify), fExistingIsNotUpToDate(true),
1063 fCacheFileInFinalLocation(rootPath[0] == '\0'), fCacheFilePath(NULL),
1064 fExistingCacheForVerification(NULL), fDyldBaseAddress(dyldBaseAddress),
1065 fOffsetOfBindInfoInCombinedLinkedit(0), fOffsetOfWeakBindInfoInCombinedLinkedit(0),
1066 fOffsetOfLazyBindInfoInCombinedLinkedit(0), fOffsetOfExportInfoInCombinedLinkedit(0),
1067 fOffsetOfOldSymbolTableInfoInCombinedLinkedit(0), fSizeOfOldSymbolTableInfoInCombinedLinkedit(0),
1068 fOffsetOfOldExternalRelocationsInCombinedLinkedit(0), fSizeOfOldExternalRelocationsInCombinedLinkedit(0),
1069 fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
1070 fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
1071 fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0),
1072 fOffsetOfDataInCodeInCombinedLinkedit(0), fSizeOfDataInCodeInCombinedLinkedit(0),
1073 fUnmappedLocalSymbolsSize(0)
1074 {
1075 if ( fArchGraph->getArchPair().arch != arch() )
1076 throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph->getArchPair().arch, arch());
1077
1078 // build vector of all shared dylibs
1079 unsigned int aliasCount = 0;
1080 std::set<const MachOLayoutAbstraction*>& dylibs = fArchGraph->getSharedDylibs();
1081 ArchGraph::StringToString& aliases = fArchGraph->getDylibAliases();
1082 for(std::set<const MachOLayoutAbstraction*>::iterator it = dylibs.begin(); it != dylibs.end(); ++it) {
1083 const MachOLayoutAbstraction* lib = *it;
1084 LayoutInfo temp;
1085 temp.layout = lib;
1086 temp.info.address = 0;
1087 temp.info.inode = lib->getInode();
1088 temp.info.modTime = lib->getLastModTime();
1089 if ( iPhoneOS ) {
1090 temp.info.inode = pathHash(lib->getID().name);
1091 temp.info.modTime = 0;
1092 }
1093 temp.info.pathFileOffset = lib->getNameFileOffset(); // for now this is the offset within the dylib
1094 for(ArchGraph::StringToString::iterator ait = aliases.begin(); ait != aliases.end(); ++ait) {
1095 if ( strcmp(ait->second, lib->getID().name) == 0 ) {
1096 temp.aliases.push_back(ait->first);
1097 ++aliasCount;
1098 }
1099 }
1100 fDylibs.push_back(temp);
1101 }
1102
1103 // create path to cache file
1104 char cachePathCanonical[MAXPATHLEN];
1105 strcpy(cachePathCanonical, cacheDir);
1106 if ( cachePathCanonical[strlen(cachePathCanonical)-1] != '/' )
1107 strcat(cachePathCanonical, "/");
1108 strcat(cachePathCanonical, DYLD_SHARED_CACHE_BASE_NAME);
1109 strcat(cachePathCanonical, cacheFileSuffix(optimize, fArchGraph->archName()));
1110 char cachePath[MAXPATHLEN];
1111 if ( explicitCacheDir ) {
1112 fCacheFilePath = strdup(cachePathCanonical);
1113 }
1114 else if ( overlayPaths.size() == 1 ) {
1115 // if no -cache_dir and exactly on -overlay, write cache file into that overlay dir
1116 strcpy(cachePath, overlayPaths[0]);
1117 strcat(cachePath, "/");
1118 strcat(cachePath, cachePathCanonical);
1119 fCacheFilePath = strdup(cachePath);
1120 }
1121 else if ( rootPath[0] != '\0' ) {
1122 strcpy(cachePath, rootPath);
1123 strcat(cachePath, "/");
1124 strcat(cachePath, cachePathCanonical);
1125 fCacheFilePath = strdup(cachePath);
1126 }
1127 else {
1128 fCacheFilePath = strdup(cachePathCanonical);
1129 }
1130
1131 // If the path we are writing to is trusted then our sources need to be trusted
1132 // <rdar://problem/21166835> Can't update the update_dyld_shared_cache on a non-boot volume
1133 rootless = rootless_check_trusted(fCacheFilePath);
1134
1135 if ( overlayPaths.size() == 1 ) {
1136 // in overlay mode if there already is a cache file in the overlay,
1137 // check if it is up to date.
1138 struct stat stat_buf;
1139 if ( stat(fCacheFilePath, &stat_buf) == 0 ) {
1140 fExistingIsNotUpToDate = this->notUpToDate(fCacheFilePath, aliasCount);
1141 }
1142 else if ( rootPath[0] != '\0' ) {
1143 // using -root and -overlay, but no cache file in overlay, check one in -root
1144 char cachePathRoot[MAXPATHLEN];
1145 strcpy(cachePathRoot, rootPath);
1146 strcat(cachePathRoot, "/");
1147 strcat(cachePathRoot, cachePathCanonical);
1148 fExistingIsNotUpToDate = this->notUpToDate(cachePathRoot, aliasCount);
1149 }
1150 else {
1151 // uisng -overlay, but no cache file in overlay, check one in boot volume
1152 fExistingIsNotUpToDate = this->notUpToDate(cachePathCanonical, aliasCount);
1153 }
1154 }
1155 else {
1156 fExistingIsNotUpToDate = this->notUpToDate(fCacheFilePath, aliasCount);
1157 }
1158
1159 // sort shared dylibs
1160 if ( verify ) {
1161 // already sorted by notUpToDate()
1162 }
1163 else if ( alphaSort ) {
1164 std::sort(fDylibs.begin(), fDylibs.end(), ByNameSorter());
1165 }
1166 else {
1167 // random sort for Address Space Randomization
1168 std::map<const MachOLayoutAbstraction*, uint32_t> map;
1169 for(typename std::vector<struct LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it)
1170 map[it->layout] = arc4random();
1171 std::sort(fDylibs.begin(), fDylibs.end(), Sorter(map));
1172 }
1173
1174 // assign segments in each dylib a new address
1175 this->assignNewBaseAddresses(verify);
1176
1177 // calculate where string pool offset will start
1178 // calculate cache file header size
1179 fHeaderSize = sizeof(dyld_cache_header)
1180 + fMappings.size()*sizeof(shared_file_mapping_np)
1181 + (fDylibs.size()+aliasCount)*sizeof(dyld_cache_image_info);
1182 const uint64_t baseHeaderSize = fHeaderSize;
1183 //fprintf(stderr, "aliasCount=%d, fHeaderSize=0x%08X\n", aliasCount, fHeaderSize);
1184 // build list of aliases and compute where each ones path string will go
1185 for(typename std::vector<struct LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1186 for(std::vector<const char*>::const_iterator ait = it->aliases.begin(); ait != it->aliases.end(); ++ait) {
1187 LayoutInfo temp = *it;
1188 // alias looks just like real dylib, but has a different name string
1189 const char* aliasPath = *ait;
1190 temp.aliases.clear();
1191 temp.aliases.push_back(aliasPath);
1192 temp.info.pathFileOffset = fHeaderSize;
1193 if ( iPhoneOS ) {
1194 temp.info.inode = pathHash(aliasPath);
1195 temp.info.modTime = 0;
1196 }
1197 fDylibAliases.push_back(temp);
1198 fHeaderSize += strlen(aliasPath)+1;
1199 }
1200 }
1201 std::sort(fDylibAliases.begin(), fDylibAliases.end(), ByNameSorter());
1202 //fprintf(stderr, "fHeaderSize=0x%08X, fDylibAliases.size()=%lu\n", fHeaderSize, fDylibAliases.size());
1203 fHeaderSize = pageAlign(fHeaderSize);
1204
1205 // check that cache we are about to create for verification purposes has same layout as existing cache
1206 if ( verify ) {
1207 // if no existing cache, say so
1208 if ( fExistingCacheForVerification == NULL ) {
1209 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
1210 getpid(), fArchGraph->archName());
1211 }
1212 const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)fExistingCacheForVerification;
1213 const dyldCacheImageInfo<E>* cacheEntry = (dyldCacheImageInfo<E>*)(fExistingCacheForVerification + header->imagesOffset());
1214 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++cacheEntry) {
1215 if ( cacheEntry->address() != it->layout->getSegments()[0].newAddress() ) {
1216 throwf("update_dyld_shared_cache[%u] warning: for arch=%s, could not verify cache because start address of %s is 0x%llX in cache, but should be 0x%llX\n",
1217 getpid(), fArchGraph->archName(), it->layout->getID().name, cacheEntry->address(), it->layout->getSegments()[0].newAddress());
1218 }
1219 }
1220 }
1221
1222
1223 if ( fHeaderSize > FIRST_DYLIB_TEXT_OFFSET )
1224 throwf("header size overflow: allowed=0x%08X, base=0x%08llX, aliases=0x%08llX", FIRST_DYLIB_TEXT_OFFSET, baseHeaderSize, fHeaderSize-baseHeaderSize);
1225 }
1226
1227
1228 template <typename A>
1229 uint64_t SharedCache<A>::getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide)
1230 {
1231 return proposedNewAddress;
1232 }
1233
1234 template <typename A>
1235 uint64_t SharedCache<A>::pathHash(const char* path)
1236 {
1237 uint64_t sum = 0;
1238 for (const char* s=path; *s != '\0'; ++s)
1239 sum += sum*4 + *s;
1240 return sum;
1241 }
1242
1243
1244 template <typename A>
1245 void SharedCache<A>::assignNewBaseAddresses(bool verify)
1246 {
1247 // first layout TEXT for dylibs
1248 const uint64_t startExecuteAddress = sharedRegionStartAddress();
1249 uint64_t currentExecuteAddress = startExecuteAddress + FIRST_DYLIB_TEXT_OFFSET;
1250 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1251 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
1252 for (int i=0; i < segs.size(); ++i) {
1253 MachOLayoutAbstraction::Segment& seg = segs[i];
1254 seg.reset();
1255 if ( seg.executable() && !seg.writable() ) {
1256 // <rdar://problem/15947734> Some dylib require extra alignment
1257 currentExecuteAddress = (currentExecuteAddress + seg.alignment() - 1) & (-seg.alignment());
1258 // __TEXT segment
1259 if ( it->info.address == 0 )
1260 it->info.address = currentExecuteAddress;
1261 seg.setNewAddress(currentExecuteAddress);
1262 currentExecuteAddress += pageAlign(seg.size());
1263 }
1264 }
1265 }
1266 // align __TEXT region
1267 currentExecuteAddress = regionAlign(currentExecuteAddress);
1268
1269 #define DENSE_PACK 0
1270 // layout __DATA* segments
1271 std::vector<MachOLayoutAbstraction::Segment*> dataSegs;
1272 std::vector<MachOLayoutAbstraction::Segment*> dataConstSegs;
1273 std::vector<MachOLayoutAbstraction::Segment*> dataDirtySegs;
1274 const uint64_t startWritableAddress = sharedRegionStartWritableAddress(currentExecuteAddress);
1275 uint64_t currentWritableAddress = startWritableAddress;
1276 for (const LayoutInfo& info : fDylibs ) {
1277 for (MachOLayoutAbstraction::Segment& seg : ((MachOLayoutAbstraction*)(info.layout))->getSegments()) {
1278 if ( seg.writable() ) {
1279 if ( seg.executable() )
1280 throw "found writable and executable segment";
1281 seg.reset();
1282 if ( strcmp(seg.name(), "__DATA_CONST") == 0 )
1283 dataConstSegs.push_back(&seg);
1284 else if ( strcmp(seg.name(), "__DATA_DIRTY") == 0 )
1285 dataDirtySegs.push_back(&seg);
1286 else
1287 dataSegs.push_back(&seg);
1288 }
1289 }
1290 }
1291 // coalesce all __DATA_CONST segments
1292 for (MachOLayoutAbstraction::Segment* seg : dataConstSegs) {
1293 #if DENSE_PACK
1294 // start segment at needed alignment
1295 currentWritableAddress = (currentWritableAddress + seg->sectionsAlignment() - 1) & (-seg->sectionsAlignment());
1296 seg->setNewAddress(currentWritableAddress);
1297 // pack together
1298 uint64_t justSectionsSize = seg->sectionsSize();
1299 currentWritableAddress = seg->newAddress() + justSectionsSize;
1300 seg->setSize(justSectionsSize);
1301 if ( seg->fileSize() > justSectionsSize )
1302 seg->setFileSize(justSectionsSize);
1303 #else
1304 seg->setNewAddress(currentWritableAddress);
1305 // pack to 4KB pages
1306 currentWritableAddress = pageAlign4KB(seg->newAddress() + seg->size());
1307 #endif
1308 }
1309 #if DENSE_PACK
1310 currentWritableAddress = pageAlign4KB(currentWritableAddress);
1311 #endif
1312 // coalesce all __DATA segments
1313 for (MachOLayoutAbstraction::Segment* seg : dataSegs) {
1314 #if DENSE_PACK
1315 // start segment at needed alignment
1316 currentWritableAddress = (currentWritableAddress + seg->sectionsAlignment() - 1) & (-seg->sectionsAlignment());
1317 seg->setNewAddress(currentWritableAddress);
1318 // pack together
1319 uint64_t justSectionsSize = seg->sectionsSize();
1320 currentWritableAddress = seg->newAddress() + justSectionsSize;
1321 seg->setSize(justSectionsSize);
1322 if ( seg->fileSize() > justSectionsSize )
1323 seg->setFileSize(justSectionsSize);
1324 #else
1325 seg->setNewAddress(currentWritableAddress);
1326 // pack to 4KB pages
1327 currentWritableAddress = pageAlign4KB(seg->newAddress() + seg->size());
1328 #endif
1329 }
1330 #if DENSE_PACK
1331 currentWritableAddress = pageAlign4KB(currentWritableAddress);
1332 #endif
1333 // coalesce all __DATA_DIRTY segments
1334 for (MachOLayoutAbstraction::Segment* seg : dataDirtySegs) {
1335 // start segment at needed alignment
1336 currentWritableAddress = (currentWritableAddress + seg->sectionsAlignment() - 1) & (-seg->sectionsAlignment());
1337 seg->setNewAddress(currentWritableAddress);
1338 // pack together
1339 uint64_t justSectionsSize = seg->sectionsSize();
1340 currentWritableAddress = seg->newAddress() + justSectionsSize;
1341 seg->setSize(justSectionsSize);
1342 if ( seg->fileSize() > justSectionsSize )
1343 seg->setFileSize(justSectionsSize);
1344 }
1345 // align __DATA region
1346 currentWritableAddress = regionAlign(currentWritableAddress);
1347
1348 // layout all read-only (but not LINKEDIT) segments
1349 const uint64_t startReadOnlyAddress = sharedRegionStartReadOnlyAddress(currentWritableAddress, currentExecuteAddress);
1350 uint64_t currentReadOnlyAddress = startReadOnlyAddress;
1351 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1352 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
1353 for(int i=0; i < segs.size(); ++i) {
1354 MachOLayoutAbstraction::Segment& seg = segs[i];
1355 if ( seg.readable() && !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") != 0) ) {
1356 // __UNICODE segment
1357 seg.setNewAddress(currentReadOnlyAddress);
1358 currentReadOnlyAddress += pageAlign(seg.size());
1359 }
1360 }
1361 }
1362
1363 // layout all LINKEDIT segments at end of all read-only segments
1364 currentReadOnlyAddress = regionAlign(currentReadOnlyAddress); // <rdar://problem/16491435>
1365 fLinkEditsStartAddress = currentReadOnlyAddress;
1366 fFirstLinkEditSegment = NULL;
1367 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1368 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
1369 for(int i=0; i < segs.size(); ++i) {
1370 MachOLayoutAbstraction::Segment& seg = segs[i];
1371 if ( seg.readable() && !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
1372 if ( fFirstLinkEditSegment == NULL )
1373 fFirstLinkEditSegment = &seg;
1374 seg.setNewAddress(currentReadOnlyAddress);
1375 currentReadOnlyAddress += pageAlign(seg.size());
1376 }
1377 }
1378 }
1379 fLinkEditsTotalUnoptimizedSize = pageAlign(currentReadOnlyAddress - fLinkEditsStartAddress);
1380
1381 // populate large mappings
1382 uint64_t cacheFileOffset = 0;
1383 if ( currentExecuteAddress > startExecuteAddress ) {
1384 shared_file_mapping_np executeMapping;
1385 executeMapping.sfm_address = startExecuteAddress;
1386 executeMapping.sfm_size = currentExecuteAddress - startExecuteAddress;
1387 executeMapping.sfm_file_offset = cacheFileOffset;
1388 executeMapping.sfm_max_prot = VM_PROT_READ | VM_PROT_EXECUTE;
1389 executeMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_EXECUTE;
1390 fMappings.push_back(executeMapping);
1391 cacheFileOffset += executeMapping.sfm_size;
1392
1393 shared_file_mapping_np writableMapping;
1394 writableMapping.sfm_address = startWritableAddress;
1395 writableMapping.sfm_size = currentWritableAddress - startWritableAddress;
1396 writableMapping.sfm_file_offset = cacheFileOffset;
1397 writableMapping.sfm_max_prot = VM_PROT_READ | VM_PROT_WRITE;
1398 writableMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_WRITE;
1399 fMappings.push_back(writableMapping);
1400 cacheFileOffset += writableMapping.sfm_size;
1401
1402 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
1403 shared_file_mapping_np readOnlyMapping;
1404 readOnlyMapping.sfm_address = startReadOnlyAddress;
1405 readOnlyMapping.sfm_size = currentReadOnlyAddress - startReadOnlyAddress;
1406 readOnlyMapping.sfm_file_offset = cacheFileOffset;
1407 readOnlyMapping.sfm_max_prot = VM_PROT_READ;
1408 readOnlyMapping.sfm_init_prot = VM_PROT_READ;
1409 fMappings.push_back(readOnlyMapping);
1410 cacheFileOffset += readOnlyMapping.sfm_size;
1411 }
1412 else {
1413 // empty cache
1414 shared_file_mapping_np cacheHeaderMapping;
1415 cacheHeaderMapping.sfm_address = startExecuteAddress;
1416 cacheHeaderMapping.sfm_size = FIRST_DYLIB_TEXT_OFFSET;
1417 cacheHeaderMapping.sfm_file_offset = cacheFileOffset;
1418 cacheHeaderMapping.sfm_max_prot = VM_PROT_READ;
1419 cacheHeaderMapping.sfm_init_prot = VM_PROT_READ;
1420 fMappings.push_back(cacheHeaderMapping);
1421 cacheFileOffset += cacheHeaderMapping.sfm_size;
1422 }
1423 }
1424
1425
1426 template <typename A>
1427 uint64_t SharedCache<A>::cacheFileOffsetForVMAddress(uint64_t vmaddr) const
1428 {
1429 for(std::vector<shared_file_mapping_np>::const_iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
1430 if ( (it->sfm_address <= vmaddr) && (vmaddr < it->sfm_address+it->sfm_size) )
1431 return it->sfm_file_offset + vmaddr - it->sfm_address;
1432 }
1433 throwf("address 0x%0llX is not in cache", vmaddr);
1434 }
1435
1436 template <typename A>
1437 uint64_t SharedCache<A>::VMAddressForCacheFileOffset(uint64_t offset) const
1438 {
1439 for(std::vector<shared_file_mapping_np>::const_iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
1440 if ( (it->sfm_file_offset <= offset) && (offset < it->sfm_file_offset+it->sfm_size) )
1441 return it->sfm_address + offset - it->sfm_file_offset;
1442 }
1443 throwf("offset 0x%0llX is not in cache", offset);
1444 }
1445
1446 template <typename A>
1447 void *SharedCache<A>::mappedAddressForVMAddress(uint64_t vmaddr)
1448 {
1449 if (!vmaddr) return NULL;
1450 else return fInMemoryCache + cacheFileOffsetForVMAddress(vmaddr);
1451 }
1452
1453 template <typename A>
1454 uint64_t SharedCache<A>::VMAddressForMappedAddress(const void *mapaddr)
1455 {
1456 if (!mapaddr) return 0;
1457 uint64_t offset = (uint8_t *)mapaddr - (uint8_t *)fInMemoryCache;
1458 return VMAddressForCacheFileOffset(offset);
1459 }
1460
1461
1462 template <typename A>
1463 bool SharedCache<A>::notUpToDate(const void* cache, unsigned int aliasCount)
1464 {
1465 dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
1466 // not valid if header signature is wrong
1467 const char* archPairName = fArchGraph->archName();
1468 char temp[16];
1469 strcpy(temp, "dyld_v1 ");
1470 strcpy(&temp[15-strlen(archPairName)], archPairName);
1471 if ( strcmp(header->magic(), temp) != 0 ) {
1472 if ( fVerify ) {
1473 fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archPairName);
1474 return false;
1475 }
1476 else {
1477 fprintf(stderr, "update_dyld_shared_cache[%u] updating cache because current cache file has invalid header\n", getpid());
1478 return true;
1479 }
1480 }
1481 // not valid if count of images does not match current images needed
1482 if ( header->imagesCount() != (fDylibs.size()+aliasCount) ) {
1483 if ( fVerify ) {
1484 fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archPairName);
1485 return false;
1486 }
1487 else {
1488 fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archPairName);
1489 return true;
1490 }
1491 }
1492 // get end of TEXT region
1493 const dyldCacheFileMapping<E>* textMapping = (dyldCacheFileMapping<E>*)((uint8_t*)cache+sizeof(dyldCacheHeader<E>));
1494 const uint32_t textSize = textMapping->size();
1495
1496 // verify every dylib in constructed graph is in existing cache with same inode and modTime
1497 std::map<const MachOLayoutAbstraction*, uint32_t> sortingMap;
1498 const dyldCacheImageInfo<E>* imagesStart = (dyldCacheImageInfo<E>*)((uint8_t*)cache + header->imagesOffset());
1499 const dyldCacheImageInfo<E>* imagesEnd = &imagesStart[header->imagesCount()];
1500 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1501 bool found = false;
1502 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
1503 for(const dyldCacheImageInfo<E>* cacheEntry = imagesStart; cacheEntry < imagesEnd; ++cacheEntry) {
1504 if ( fVerify ) {
1505 if ( cacheEntry->pathFileOffset() > textSize ) {
1506 throwf("update_dyld_shared_cache[%u]: for arch=%s, image entries corrupt, bad path offset in %s\n",
1507 getpid(), archPairName, it->layout->getID().name);
1508 }
1509 // in -verify mode, just match by path and warn if file looks different
1510 if ( strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0 ) {
1511 found = true;
1512 sortingMap[it->layout] = cacheEntry-imagesStart;
1513 if ( (cacheEntry->inode() != it->info.inode) || (cacheEntry->modTime() != it->info.modTime) ) {
1514 fprintf(stderr, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n",
1515 getpid(), archPairName, it->layout->getID().name);
1516 }
1517 break;
1518 }
1519 }
1520 else {
1521 if ( cacheEntry->pathFileOffset() > textSize ) {
1522 // cache corrupt, needs to be regenerated
1523 return true;
1524 }
1525 // in normal update mode, everything has to match for cache to be up-to-date
1526 if ( (cacheEntry->inode() == it->info.inode)
1527 && (cacheEntry->modTime() == it->info.modTime)
1528 && (strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0) ) {
1529 found = true;
1530 break;
1531 }
1532 }
1533 }
1534 if ( !found ) {
1535 if ( fVerify ) {
1536 throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archPairName, it->layout->getID().name);
1537 }
1538 else {
1539 fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archPairName, it->layout->getID().name);
1540 return true;
1541 }
1542 }
1543 }
1544 // all dylibs in existing cache file match those determined need to be in shared cache
1545 if ( fVerify ) {
1546 // sort fDylibs to match existing cache file so we can compare content
1547 std::sort(fDylibs.begin(), fDylibs.end(), Sorter(sortingMap));
1548 //fprintf(stderr, "dylibs sorted like existing cache:\n");
1549 //for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1550 // fprintf(stderr," %s\n", it->layout->getID().name);
1551 //}
1552 // do regenerate a new cache so we can compare content with existing
1553 return true;
1554 }
1555 else {
1556 // existing cache file is up-to-date, don't need to regenerate
1557 return false;
1558 }
1559 }
1560
1561
1562 template <typename A>
1563 bool SharedCache<A>::notUpToDate(const char* path, unsigned int aliasCount)
1564 {
1565 // mmap existing cache file
1566 int fd = ::open(path, O_RDONLY);
1567 if ( fd == -1 )
1568 return true;
1569 struct stat stat_buf;
1570 ::fstat(fd, &stat_buf);
1571 uint32_t cacheFileSize = stat_buf.st_size;
1572 uint32_t cacheAllocatedSize = pageAlign(cacheFileSize);
1573 uint8_t* mappingAddr = NULL;
1574 if ( vm_allocate(mach_task_self(), (vm_address_t*)(&mappingAddr), cacheAllocatedSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
1575 throwf("can't vm_allocate cache of size %u", cacheFileSize);
1576 // <rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
1577 (void)fcntl(fd, F_NOCACHE, 1);
1578 ssize_t readResult = pread(fd, mappingAddr, cacheFileSize, 0);
1579 if ( readResult != cacheFileSize )
1580 throwf("can't read all of existing cache file (%lu of %u): %s", readResult, cacheFileSize, path);
1581 ::close(fd);
1582
1583 // validate it
1584 bool result = this->notUpToDate(mappingAddr, aliasCount);
1585 if ( fVerify ) {
1586 // don't unmap yet, leave so it can be verified later
1587 fExistingCacheForVerification = mappingAddr;
1588 }
1589 else {
1590 // unmap
1591 vm_deallocate(mach_task_self(), (vm_address_t)mappingAddr, cacheAllocatedSize);
1592 if ( verbose && !result )
1593 fprintf(stderr, "update_dyld_shared_cache: %s is up-to-date\n", path);
1594 }
1595 return result;
1596 }
1597
1598
1599
1600 template <typename A>
1601 class LinkEditOptimizer
1602 {
1603 public:
1604 LinkEditOptimizer(const MachOLayoutAbstraction&, const SharedCache<A>&, uint8_t*, StringPool&);
1605 virtual ~LinkEditOptimizer() {}
1606
1607 void copyBindInfo(uint32_t&);
1608 void copyWeakBindInfo(uint32_t&);
1609 void copyLazyBindInfo(uint32_t&);
1610 void copyExportInfo(uint32_t&);
1611 void copyLocalSymbols(uint32_t symbolTableOffset, uint32_t&, bool dontMapLocalSymbols,
1612 uint8_t* cacheStart, StringPool& unmappedLocalsStringPool,
1613 std::vector<macho_nlist<typename A::P> >& unmappedSymbols,
1614 std::vector<LocalSymbolInfo>& info);
1615 void copyExportedSymbols(uint32_t symbolTableOffset, uint32_t&);
1616 void copyImportedSymbols(uint32_t symbolTableOffset, uint32_t&);
1617 void copyExternalRelocations(uint32_t& offset);
1618 void copyIndirectSymbolTable(uint32_t& offset);
1619 void copyFunctionStarts(uint32_t& offset);
1620 void copyDataInCode(uint32_t& offset);
1621 void updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset,
1622 uint32_t linkEditsFileOffset, bool keepSignatures);
1623
1624
1625 protected:
1626 typedef typename A::P P;
1627 typedef typename A::P::E E;
1628 typedef typename A::P::uint_t pint_t;
1629
1630 private:
1631
1632 const SharedCache<A>& fSharedCache;
1633 const macho_header<P>* fHeader;
1634 uint8_t* fNewLinkEditStart;
1635 uint8_t* fLinkEditBase;
1636 const MachOLayoutAbstraction& fLayout;
1637 macho_dyld_info_command<P>* fDyldInfo;
1638 macho_dysymtab_command<P>* fDynamicSymbolTable;
1639 macho_linkedit_data_command<P>* fFunctionStarts;
1640 macho_linkedit_data_command<P>* fDataInCode;
1641 macho_symtab_command<P>* fSymbolTableLoadCommand;
1642 const macho_nlist<P>* fSymbolTable;
1643 const char* fStrings;
1644 StringPool& fNewStringPool;
1645 std::map<uint32_t,uint32_t> fOldToNewSymbolIndexes;
1646 uint32_t fBindInfoOffsetIntoNewLinkEdit;
1647 uint32_t fBindInfoSizeInNewLinkEdit;
1648 uint32_t fWeakBindInfoOffsetIntoNewLinkEdit;
1649 uint32_t fWeakBindInfoSizeInNewLinkEdit;
1650 uint32_t fLazyBindInfoOffsetIntoNewLinkEdit;
1651 uint32_t fLazyBindInfoSizeInNewLinkEdit;
1652 uint32_t fExportInfoOffsetIntoNewLinkEdit;
1653 uint32_t fExportInfoSizeInNewLinkEdit;
1654 uint32_t fSymbolTableStartOffsetInNewLinkEdit;
1655 uint32_t fLocalSymbolsStartIndexInNewLinkEdit;
1656 uint32_t fLocalSymbolsCountInNewLinkEdit;
1657 uint32_t fExportedSymbolsStartIndexInNewLinkEdit;
1658 uint32_t fExportedSymbolsCountInNewLinkEdit;
1659 uint32_t fImportSymbolsStartIndexInNewLinkEdit;
1660 uint32_t fImportedSymbolsCountInNewLinkEdit;
1661 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit;
1662 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit;
1663 uint32_t fFunctionStartsOffsetInNewLinkEdit;
1664 uint32_t fDataInCodeOffsetInNewLinkEdit;
1665 uint32_t fUnmappedLocalSymbolsStartIndexInNewLinkEdit;
1666 uint32_t fUnmappedLocalSymbolsCountInNewLinkEdit;
1667 };
1668
1669
1670
1671 template <typename A>
1672 LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, const SharedCache<A>& sharedCache, uint8_t* newLinkEdit, StringPool& stringPool)
1673 : fSharedCache(sharedCache), fLayout(layout), fLinkEditBase(NULL), fNewLinkEditStart(newLinkEdit), fDyldInfo(NULL),
1674 fDynamicSymbolTable(NULL), fFunctionStarts(NULL), fDataInCode(NULL),
1675 fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
1676 fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
1677 fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
1678 fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
1679 fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
1680 fSymbolTableStartOffsetInNewLinkEdit(0),
1681 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
1682 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
1683 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
1684 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
1685 fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0),
1686 fUnmappedLocalSymbolsStartIndexInNewLinkEdit(0), fUnmappedLocalSymbolsCountInNewLinkEdit(0)
1687
1688 {
1689 fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
1690
1691 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
1692 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
1693 const MachOLayoutAbstraction::Segment& seg = *it;
1694 if ( strcmp(seg.name(), "__LINKEDIT") == 0 )
1695 fLinkEditBase = (uint8_t*)seg.mappedAddress() - seg.fileOffset();
1696 }
1697 if ( fLinkEditBase == NULL )
1698 throw "no __LINKEDIT segment";
1699
1700 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
1701 const uint32_t cmd_count = fHeader->ncmds();
1702 const macho_load_command<P>* cmd = cmds;
1703 for (uint32_t i = 0; i < cmd_count; ++i) {
1704 switch (cmd->cmd()) {
1705 case LC_SYMTAB:
1706 {
1707 fSymbolTableLoadCommand = (macho_symtab_command<P>*)cmd;
1708 fSymbolTable = (macho_nlist<P>*)(&fLinkEditBase[fSymbolTableLoadCommand->symoff()]);
1709 fStrings = (char*)&fLinkEditBase[fSymbolTableLoadCommand->stroff()];
1710 }
1711 break;
1712 case LC_DYSYMTAB:
1713 fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
1714 break;
1715 case LC_DYLD_INFO:
1716 case LC_DYLD_INFO_ONLY:
1717 fDyldInfo = (macho_dyld_info_command<P>*)cmd;
1718 break;
1719 case LC_FUNCTION_STARTS:
1720 fFunctionStarts = (macho_linkedit_data_command<P>*)cmd;
1721 case LC_DATA_IN_CODE:
1722 fDataInCode = (macho_linkedit_data_command<P>*)cmd;
1723 break;
1724 }
1725 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
1726 }
1727 if ( fSymbolTable == NULL )
1728 throw "no LC_SYMTAB";
1729 if ( fDynamicSymbolTable == NULL )
1730 throw "no LC_DYSYMTAB";
1731
1732 }
1733
1734
1735 template <typename A>
1736 class SymbolSorter
1737 {
1738 public:
1739 typedef typename A::P P;
1740 SymbolSorter(const StringPool& pool) : fStringPool(pool) {}
1741 bool operator()(const macho_nlist<P>& left, const macho_nlist<P>& right) {
1742 return (strcmp(fStringPool.stringAtIndex(left.n_strx()) , fStringPool.stringAtIndex(right.n_strx())) < 0);
1743 }
1744
1745 private:
1746 const StringPool& fStringPool;
1747 };
1748
1749
1750 template <typename A>
1751 void LinkEditOptimizer<A>::copyBindInfo(uint32_t& offset)
1752 {
1753 if ( (fDyldInfo != NULL) && (fDyldInfo->bind_off() != 0) ) {
1754 fBindInfoOffsetIntoNewLinkEdit = offset;
1755 fBindInfoSizeInNewLinkEdit = fDyldInfo->bind_size();
1756 memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->bind_off()], fDyldInfo->bind_size());
1757 offset += fDyldInfo->bind_size();
1758 }
1759 }
1760
1761 template <typename A>
1762 void LinkEditOptimizer<A>::copyWeakBindInfo(uint32_t& offset)
1763 {
1764 if ( (fDyldInfo != NULL) && (fDyldInfo->weak_bind_off() != 0) ) {
1765 fWeakBindInfoOffsetIntoNewLinkEdit = offset;
1766 fWeakBindInfoSizeInNewLinkEdit = fDyldInfo->weak_bind_size();
1767 memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->weak_bind_off()], fDyldInfo->weak_bind_size());
1768 offset += fDyldInfo->weak_bind_size();
1769 }
1770 }
1771
1772 template <typename A>
1773 void LinkEditOptimizer<A>::copyLazyBindInfo(uint32_t& offset)
1774 {
1775 if ( (fDyldInfo != NULL) && (fDyldInfo->lazy_bind_off() != 0) ) {
1776 fLazyBindInfoOffsetIntoNewLinkEdit = offset;
1777 fLazyBindInfoSizeInNewLinkEdit = fDyldInfo->lazy_bind_size();
1778 memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->lazy_bind_off()], fDyldInfo->lazy_bind_size());
1779 offset += fDyldInfo->lazy_bind_size();
1780 }
1781 }
1782
1783 template <typename A>
1784 void LinkEditOptimizer<A>::copyExportInfo(uint32_t& offset)
1785 {
1786 if ( (fDyldInfo != NULL) && (fLayout.getDyldInfoExports() != NULL) ) {
1787 fExportInfoOffsetIntoNewLinkEdit = offset;
1788 fExportInfoSizeInNewLinkEdit = fDyldInfo->export_size();
1789 memcpy(fNewLinkEditStart+offset, fLayout.getDyldInfoExports(), fDyldInfo->export_size());
1790 offset += fDyldInfo->export_size();
1791 }
1792 }
1793
1794
1795 template <typename A>
1796 void LinkEditOptimizer<A>::copyLocalSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex, bool dontMapLocalSymbols, uint8_t* cacheStart,
1797 StringPool& unmappedLocalsStringPool, std::vector<macho_nlist<P> >& unmappedSymbols,
1798 std::vector<LocalSymbolInfo>& dylibInfos)
1799 {
1800 fLocalSymbolsStartIndexInNewLinkEdit = symbolIndex;
1801 LocalSymbolInfo localInfo;
1802 localInfo.dylibOffset = ((uint8_t*)fHeader) - cacheStart;
1803 localInfo.nlistStartIndex = unmappedSymbols.size();
1804 localInfo.nlistCount = 0;
1805 fSymbolTableStartOffsetInNewLinkEdit = symbolTableOffset + symbolIndex*sizeof(macho_nlist<P>);
1806 macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
1807 const macho_nlist<P>* const firstLocal = &fSymbolTable[fDynamicSymbolTable->ilocalsym()];
1808 const macho_nlist<P>* const lastLocal = &fSymbolTable[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
1809 uint32_t oldIndex = fDynamicSymbolTable->ilocalsym();
1810 for (const macho_nlist<P>* entry = firstLocal; entry < lastLocal; ++entry, ++oldIndex) {
1811 // <rdar://problem/12237639> don't copy stab symbols
1812 if ( (entry->n_sect() != NO_SECT) && ((entry->n_type() & N_STAB) == 0) ) {
1813 const char* name = &fStrings[entry->n_strx()];
1814 macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
1815 *newSymbolEntry = *entry;
1816 if ( dontMapLocalSymbols ) {
1817 // if local in __text, add <redacted> symbol name to shared cache so backtraces don't have bogus names
1818 if ( entry->n_sect() == 1 ) {
1819 newSymbolEntry->set_n_strx(fNewStringPool.addUnique("<redacted>"));
1820 ++symbolIndex;
1821 }
1822 // copy local symbol to unmmapped locals area
1823 unmappedSymbols.push_back(*entry);
1824 unmappedSymbols.back().set_n_strx(unmappedLocalsStringPool.addUnique(name));
1825 }
1826 else {
1827 newSymbolEntry->set_n_strx(fNewStringPool.addUnique(name));
1828 ++symbolIndex;
1829 }
1830 }
1831 }
1832 fLocalSymbolsCountInNewLinkEdit = symbolIndex - fLocalSymbolsStartIndexInNewLinkEdit;
1833 localInfo.nlistCount = unmappedSymbols.size() - localInfo.nlistStartIndex;
1834 dylibInfos.push_back(localInfo);
1835 //fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1836 }
1837
1838
1839 template <typename A>
1840 void LinkEditOptimizer<A>::copyExportedSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
1841 {
1842 fExportedSymbolsStartIndexInNewLinkEdit = symbolIndex;
1843 macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
1844 const macho_nlist<P>* const firstExport = &fSymbolTable[fDynamicSymbolTable->iextdefsym()];
1845 const macho_nlist<P>* const lastExport = &fSymbolTable[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
1846 uint32_t oldIndex = fDynamicSymbolTable->iextdefsym();
1847 for (const macho_nlist<P>* entry = firstExport; entry < lastExport; ++entry, ++oldIndex) {
1848 if ( ((entry->n_type() & N_TYPE) == N_SECT) && (strncmp(&fStrings[entry->n_strx()], ".objc_", 6) != 0)
1849 && (strncmp(&fStrings[entry->n_strx()], "$ld$", 4) != 0) ) {
1850 macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
1851 *newSymbolEntry = *entry;
1852 newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
1853 fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
1854 ++symbolIndex;
1855 }
1856 }
1857 fExportedSymbolsCountInNewLinkEdit = symbolIndex - fExportedSymbolsStartIndexInNewLinkEdit;
1858 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1859 // sort by name, so that dyld does not need a toc
1860 macho_nlist<P>* newSymbolsStart = &newSymbolTableStart[fExportedSymbolsStartIndexInNewLinkEdit];
1861 macho_nlist<P>* newSymbolsEnd = &newSymbolTableStart[fExportedSymbolsStartIndexInNewLinkEdit+fExportedSymbolsCountInNewLinkEdit];
1862 std::sort(newSymbolsStart, newSymbolsEnd, SymbolSorter<A>(fNewStringPool));
1863 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1864 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1865 }
1866
1867
1868 template <typename A>
1869 void LinkEditOptimizer<A>::copyImportedSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
1870 {
1871 fImportSymbolsStartIndexInNewLinkEdit = symbolIndex;
1872 macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
1873 const macho_nlist<P>* const firstImport = &fSymbolTable[fDynamicSymbolTable->iundefsym()];
1874 const macho_nlist<P>* const lastImport = &fSymbolTable[fDynamicSymbolTable->iundefsym()+fDynamicSymbolTable->nundefsym()];
1875 uint32_t oldIndex = fDynamicSymbolTable->iundefsym();
1876 for (const macho_nlist<P>* entry = firstImport; entry < lastImport; ++entry, ++oldIndex) {
1877 if ( ((entry->n_type() & N_TYPE) == N_UNDF) && (strncmp(&fStrings[entry->n_strx()], ".objc_", 6) != 0) ) {
1878 macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
1879 *newSymbolEntry = *entry;
1880 newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
1881 fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
1882 ++symbolIndex;
1883 }
1884 }
1885 fImportedSymbolsCountInNewLinkEdit = symbolIndex - fImportSymbolsStartIndexInNewLinkEdit;
1886 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1887 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1888 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1889 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1890 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1891 }
1892
1893
1894 template <typename A>
1895 void LinkEditOptimizer<A>::copyExternalRelocations(uint32_t& offset)
1896 {
1897 fExternalRelocationsOffsetIntoNewLinkEdit = offset;
1898 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->extreloff()]);
1899 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nextrel()];
1900 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1901 macho_relocation_info<P>* newReloc = (macho_relocation_info<P>*)(&fNewLinkEditStart[offset]);
1902 *newReloc = *reloc;
1903 uint32_t newSymbolIndex = fOldToNewSymbolIndexes[reloc->r_symbolnum()];
1904 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1905 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1906 newReloc->set_r_symbolnum(newSymbolIndex);
1907 offset += sizeof(macho_relocation_info<P>);
1908 }
1909 }
1910
1911 template <typename A>
1912 void LinkEditOptimizer<A>::copyFunctionStarts(uint32_t& offset)
1913 {
1914 if ( fFunctionStarts != NULL ) {
1915 fFunctionStartsOffsetInNewLinkEdit = offset;
1916 memcpy(&fNewLinkEditStart[offset], &fLinkEditBase[fFunctionStarts->dataoff()], fFunctionStarts->datasize());
1917 offset += fFunctionStarts->datasize();
1918 }
1919 }
1920
1921 template <typename A>
1922 void LinkEditOptimizer<A>::copyDataInCode(uint32_t& offset)
1923 {
1924 if ( fDataInCode != NULL ) {
1925 fDataInCodeOffsetInNewLinkEdit = offset;
1926 memcpy(&fNewLinkEditStart[offset], &fLinkEditBase[fDataInCode->dataoff()], fDataInCode->datasize());
1927 offset += fDataInCode->datasize();
1928 }
1929 }
1930
1931
1932 template <typename A>
1933 void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
1934 {
1935 fIndirectSymbolTableOffsetInfoNewLinkEdit = offset;
1936 const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicSymbolTable->indirectsymoff()];
1937 uint32_t* newIndirectTable = (uint32_t*)&fNewLinkEditStart[offset];
1938 for (int i=0; i < fDynamicSymbolTable->nindirectsyms(); ++i) {
1939 uint32_t oldSymbolIndex = E::get32(indirectTable[i]);
1940 uint32_t newSymbolIndex = oldSymbolIndex;
1941 if ( (oldSymbolIndex != INDIRECT_SYMBOL_ABS) && (oldSymbolIndex != INDIRECT_SYMBOL_LOCAL) ) {
1942 newSymbolIndex = fOldToNewSymbolIndexes[oldSymbolIndex];
1943 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1944 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1945 }
1946 E::set32(newIndirectTable[i], newSymbolIndex);
1947 }
1948 offset += (fDynamicSymbolTable->nindirectsyms() * 4);
1949 }
1950
1951 template <typename A>
1952 void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t leSize, uint32_t stringPoolOffset,
1953 uint32_t linkEditsFileOffset, bool keepSignatures)
1954 {
1955 // set LINKEDIT segment commmand to new merged LINKEDIT
1956 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
1957 const uint32_t cmd_count = fHeader->ncmds();
1958 const macho_load_command<P>* cmd = cmds;
1959 for (uint32_t i = 0; i < cmd_count; ++i) {
1960 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1961 macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
1962 if ( strcmp(seg->segname(), "__LINKEDIT") == 0 ) {
1963 seg->set_vmaddr(newVMAddress);
1964 seg->set_vmsize(leSize);
1965 seg->set_filesize(leSize);
1966 seg->set_fileoff(linkEditsFileOffset);
1967 }
1968 else {
1969 pint_t oldFileOff = seg->fileoff();
1970 // don't alter __TEXT until <rdar://problem/7022345> is fixed
1971 if ( strcmp(seg->segname(), "__TEXT") != 0 ) {
1972 // update all other segments fileoff to be offset from start of cache file
1973 seg->set_fileoff(fSharedCache.cacheFileOffsetForVMAddress(seg->vmaddr()));
1974 }
1975 pint_t fileOffsetDelta = seg->fileoff() - oldFileOff;
1976 const MachOLayoutAbstraction::Segment* layoutSeg = fLayout.getSegment(seg->segname());
1977 if ( layoutSeg != NULL ) {
1978 //if ( seg->filesize() != layoutSeg->fileSize() ) {
1979 // fprintf(stderr, "LC filesize=0x%08llX, trimmed seg file size=0x%08llX, seg=%s, path=%s\n",
1980 // seg->filesize(), layoutSeg->fileSize(), seg->segname(), fLayout.getFilePath());
1981 //}
1982 //if ( seg->vmsize() != layoutSeg->size() ) {
1983 // fprintf(stderr, "LC vmsize=0x%08llX, trimmed seg size=0x%08llX, seg=%s, path=%s\n",
1984 // seg->vmsize(), layoutSeg->size(), seg->segname(), fLayout.getFilePath());
1985 //}
1986 seg->set_vmsize(layoutSeg->size());
1987 seg->set_filesize(layoutSeg->fileSize());
1988 }
1989 // update all sections in this segment
1990 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
1991 macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
1992 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
1993 if ( sect->offset() != 0 )
1994 sect->set_offset(sect->offset()+fileOffsetDelta);
1995 //if ( (sect->flags() & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS )
1996 // fprintf(stderr, "found initializer(s) in %s\n", fLayout.getFilePath());
1997 }
1998 }
1999 }
2000 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
2001 }
2002
2003 // update dyld_info with new offsets
2004 if ( fDyldInfo != NULL ) {
2005 fDyldInfo->set_rebase_off(0);
2006 fDyldInfo->set_rebase_size(0);
2007 fDyldInfo->set_bind_off(linkEditsFileOffset+fBindInfoOffsetIntoNewLinkEdit);
2008 fDyldInfo->set_bind_size(fBindInfoSizeInNewLinkEdit);
2009 fDyldInfo->set_weak_bind_off(linkEditsFileOffset+fWeakBindInfoOffsetIntoNewLinkEdit);
2010 fDyldInfo->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit);
2011 fDyldInfo->set_lazy_bind_off(linkEditsFileOffset+fLazyBindInfoOffsetIntoNewLinkEdit);
2012 fDyldInfo->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit);
2013 fDyldInfo->set_export_off(linkEditsFileOffset+fExportInfoOffsetIntoNewLinkEdit);
2014 fDyldInfo->set_export_size(fExportInfoSizeInNewLinkEdit);
2015
2016 // fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
2017 // fprintf(stderr, " bind_off=0x%08X\n", fDyldInfo->bind_off());
2018 // fprintf(stderr, " export_off=0x%08X\n", fDyldInfo->export_off());
2019 // fprintf(stderr, " export_size=%d\n", fDyldInfo->export_size());
2020
2021 }
2022
2023 // update symbol table and dynamic symbol table with new offsets
2024 fSymbolTableLoadCommand->set_symoff(linkEditsFileOffset+fSymbolTableStartOffsetInNewLinkEdit);
2025 fSymbolTableLoadCommand->set_nsyms(fLocalSymbolsCountInNewLinkEdit+fExportedSymbolsCountInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit);
2026 fSymbolTableLoadCommand->set_stroff(linkEditsFileOffset+stringPoolOffset);
2027 fSymbolTableLoadCommand->set_strsize(fNewStringPool.size());
2028 fDynamicSymbolTable->set_ilocalsym(0);
2029 fDynamicSymbolTable->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit);
2030 fDynamicSymbolTable->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit-fLocalSymbolsStartIndexInNewLinkEdit);
2031 fDynamicSymbolTable->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit);
2032 fDynamicSymbolTable->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit-fLocalSymbolsStartIndexInNewLinkEdit);
2033 fDynamicSymbolTable->set_nundefsym(fImportedSymbolsCountInNewLinkEdit);
2034 fDynamicSymbolTable->set_tocoff(0);
2035 fDynamicSymbolTable->set_ntoc(0);
2036 fDynamicSymbolTable->set_modtaboff(0);
2037 fDynamicSymbolTable->set_nmodtab(0);
2038 fDynamicSymbolTable->set_indirectsymoff(linkEditsFileOffset+fIndirectSymbolTableOffsetInfoNewLinkEdit);
2039 fDynamicSymbolTable->set_extreloff(linkEditsFileOffset+fExternalRelocationsOffsetIntoNewLinkEdit);
2040 fDynamicSymbolTable->set_locreloff(0);
2041 fDynamicSymbolTable->set_nlocrel(0);
2042
2043 // update function starts
2044 if ( fFunctionStarts != NULL ) {
2045 fFunctionStarts->set_dataoff(linkEditsFileOffset+fFunctionStartsOffsetInNewLinkEdit);
2046 }
2047 // update data-in-code info
2048 if ( fDataInCode != NULL ) {
2049 fDataInCode->set_dataoff(linkEditsFileOffset+fDataInCodeOffsetInNewLinkEdit);
2050 }
2051
2052 // now remove load commands no longer needed
2053 const macho_load_command<P>* srcCmd = cmds;
2054 macho_load_command<P>* dstCmd = (macho_load_command<P>*)cmds;
2055 int32_t newCount = 0;
2056 for (uint32_t i = 0; i < cmd_count; ++i) {
2057 uint32_t cmdSize = srcCmd->cmdsize();
2058 switch ( srcCmd->cmd() ) {
2059 case LC_SEGMENT_SPLIT_INFO:
2060 case LC_DYLIB_CODE_SIGN_DRS:
2061 case LC_RPATH:
2062 // don't copy
2063 break;
2064 case LC_CODE_SIGNATURE:
2065 if ( !keepSignatures )
2066 break;
2067 // otherwise fall into copy case
2068 default:
2069 memmove(dstCmd, srcCmd, cmdSize);
2070 dstCmd = (macho_load_command<P>*)(((uint8_t*)dstCmd)+cmdSize);
2071 ++newCount;
2072 break;
2073 }
2074 srcCmd = (const macho_load_command<P>*)(((uint8_t*)srcCmd)+cmdSize);
2075 }
2076 // zero out stuff removed
2077 bzero(dstCmd, (uint8_t*)srcCmd - (uint8_t*)dstCmd);
2078
2079 // update mach_header
2080 macho_header<P>* writableHeader = (macho_header<P>*)fHeader;
2081 writableHeader->set_ncmds(newCount);
2082 writableHeader->set_sizeofcmds((uint8_t*)dstCmd - ((uint8_t*)fHeader + sizeof(macho_header<P>)));
2083
2084 // this invalidates some ivars
2085 fDynamicSymbolTable = NULL;
2086 fSymbolTableLoadCommand = NULL;
2087 fDyldInfo = NULL;
2088 fSymbolTable = NULL;
2089 fStrings = NULL;
2090 }
2091
2092
2093
2094 template <typename A>
2095 uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures, bool dontMapLocalSymbols)
2096 {
2097 // allocate space for optimized LINKEDIT area
2098 uint8_t* newLinkEdit = new uint8_t[fLinkEditsTotalUnoptimizedSize];
2099 bzero(newLinkEdit, fLinkEditsTotalUnoptimizedSize);
2100
2101 // make a string pool
2102 StringPool stringPool;
2103
2104 // create optimizer object for each LINKEDIT segment
2105 std::vector<LinkEditOptimizer<A>*> optimizers;
2106 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2107 optimizers.push_back(new LinkEditOptimizer<A>(*it->layout, *this, newLinkEdit, stringPool));
2108 }
2109
2110 // rebase info is not copied because images in shared cache are never rebased
2111
2112 // copy weak bind info
2113 uint32_t offset = 0;
2114 fOffsetOfWeakBindInfoInCombinedLinkedit = offset;
2115 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2116 (*it)->copyWeakBindInfo(offset);
2117 }
2118
2119 // copy export info
2120 fOffsetOfExportInfoInCombinedLinkedit = offset;
2121 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2122 (*it)->copyExportInfo(offset);
2123 }
2124
2125 // copy bind info
2126 fOffsetOfBindInfoInCombinedLinkedit = offset;
2127 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2128 (*it)->copyBindInfo(offset);
2129 }
2130
2131 // copy lazy bind info
2132 fOffsetOfLazyBindInfoInCombinedLinkedit = offset;
2133 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2134 (*it)->copyLazyBindInfo(offset);
2135 }
2136
2137 // copy symbol table entries
2138 fOffsetOfOldSymbolTableInfoInCombinedLinkedit = offset;
2139 uint32_t symbolTableOffset = offset;
2140 uint32_t symbolTableIndex = 0;
2141 if ( dontMapLocalSymbols )
2142 fUnmappedLocalSymbols.reserve(16384);
2143 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2144 (*it)->copyLocalSymbols(symbolTableOffset, symbolTableIndex, dontMapLocalSymbols, fInMemoryCache,
2145 fUnmappedLocalsStringPool, fUnmappedLocalSymbols, fLocalSymbolInfos);
2146 (*it)->copyExportedSymbols(symbolTableOffset, symbolTableIndex);
2147 (*it)->copyImportedSymbols(symbolTableOffset, symbolTableIndex);
2148 }
2149 fSizeOfOldSymbolTableInfoInCombinedLinkedit = symbolTableIndex * sizeof(macho_nlist<typename A::P>);
2150 offset = symbolTableOffset + fSizeOfOldSymbolTableInfoInCombinedLinkedit & (-8);
2151
2152 // copy external relocations, 8-byte aligned after end of symbol table
2153 fOffsetOfOldExternalRelocationsInCombinedLinkedit = offset;
2154 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2155 (*it)->copyExternalRelocations(offset);
2156 }
2157 fSizeOfOldExternalRelocationsInCombinedLinkedit = offset - fOffsetOfOldExternalRelocationsInCombinedLinkedit;
2158
2159 // copy function starts
2160 fOffsetOfFunctionStartsInCombinedLinkedit = offset;
2161 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2162 (*it)->copyFunctionStarts(offset);
2163 }
2164 fSizeOfFunctionStartsInCombinedLinkedit = offset - fOffsetOfFunctionStartsInCombinedLinkedit;
2165
2166 // copy data-in-code info
2167 fOffsetOfDataInCodeInCombinedLinkedit = offset;
2168 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2169 (*it)->copyDataInCode(offset);
2170 }
2171 fSizeOfDataInCodeInCombinedLinkedit = offset - fOffsetOfDataInCodeInCombinedLinkedit;
2172
2173 // copy indirect symbol tables
2174 fOffsetOfOldIndirectSymbolsInCombinedLinkedit = offset;
2175 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2176 (*it)->copyIndirectSymbolTable(offset);
2177 }
2178 fSizeOfOldIndirectSymbolsInCombinedLinkedit = offset - fOffsetOfOldIndirectSymbolsInCombinedLinkedit;
2179
2180 // copy string pool
2181 fOffsetOfOldStringPoolInCombinedLinkedit = offset;
2182 memcpy(&newLinkEdit[offset], stringPool.getBuffer(), stringPool.size());
2183 fSizeOfOldStringPoolInCombinedLinkedit = stringPool.size();
2184
2185 // total new size round up to page size
2186 fLinkEditsTotalOptimizedSize = pageAlign(fOffsetOfOldStringPoolInCombinedLinkedit + fSizeOfOldStringPoolInCombinedLinkedit);
2187
2188 // choose new linkedit file offset
2189 uint32_t linkEditsFileOffset = cacheFileOffsetForVMAddress(fLinkEditsStartAddress);
2190 // uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionStartAddress();
2191
2192 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
2193 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
2194 (*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalOptimizedSize, fOffsetOfOldStringPoolInCombinedLinkedit, linkEditsFileOffset, keepSignatures);
2195 }
2196
2197 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
2198 //printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
2199
2200 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
2201 memcpy(fFirstLinkEditSegment->mappedAddress(), newLinkEdit, fLinkEditsTotalUnoptimizedSize);
2202
2203 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
2204 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2205 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
2206 for(int i=0; i < segs.size(); ++i) {
2207 MachOLayoutAbstraction::Segment& seg = segs[i];
2208 if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
2209 seg.setNewAddress(fLinkEditsStartAddress);
2210 seg.setMappedAddress(fFirstLinkEditSegment->mappedAddress());
2211 seg.setSize(fLinkEditsTotalOptimizedSize);
2212 seg.setFileSize(fLinkEditsTotalOptimizedSize);
2213 seg.setFileOffset(linkEditsFileOffset);
2214 }
2215 }
2216 }
2217
2218 // return new end of cache
2219 return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + regionAlign(fLinkEditsTotalOptimizedSize);
2220 }
2221
2222
2223 template <typename A>
2224 class ObjCSelectorUniquer
2225 {
2226 private:
2227 objc_opt::string_map fSelectorStrings;
2228 SharedCache<A> *fCache;
2229 size_t fCount;
2230
2231 public:
2232
2233 ObjCSelectorUniquer(SharedCache<A> *newCache)
2234 : fSelectorStrings()
2235 , fCache(newCache)
2236 , fCount(0)
2237 { }
2238
2239 typename A::P::uint_t visit(typename A::P::uint_t oldValue)
2240 {
2241 fCount++;
2242 const char *s = (const char *)
2243 fCache->mappedAddressForVMAddress(oldValue);
2244 objc_opt::string_map::iterator element =
2245 fSelectorStrings.insert(objc_opt::string_map::value_type(s, oldValue)).first;
2246 return (typename A::P::uint_t)element->second;
2247 }
2248
2249 objc_opt::string_map& strings() {
2250 return fSelectorStrings;
2251 }
2252
2253 size_t count() const { return fCount; }
2254 };
2255
2256
2257 template <typename A>
2258 class ClassListBuilder
2259 {
2260 private:
2261 typedef typename A::P P;
2262
2263 objc_opt::string_map fClassNames;
2264 objc_opt::class_map fClasses;
2265 size_t fCount;
2266 HeaderInfoOptimizer<A>& fHinfos;
2267
2268 public:
2269
2270 ClassListBuilder(HeaderInfoOptimizer<A>& hinfos)
2271 : fClassNames()
2272 , fClasses()
2273 , fCount(0)
2274 , fHinfos(hinfos)
2275 { }
2276
2277 void visitClass(SharedCache<A>* cache,
2278 const macho_header<P>* header,
2279 objc_class_t<A>* cls)
2280 {
2281 if (cls->isMetaClass(cache)) return;
2282
2283 const char *name = cls->getName(cache);
2284 uint64_t name_vmaddr = cache->VMAddressForMappedAddress(name);
2285 uint64_t cls_vmaddr = cache->VMAddressForMappedAddress(cls);
2286 uint64_t hinfo_vmaddr = cache->VMAddressForMappedAddress(fHinfos.hinfoForHeader(cache, header));
2287 fClassNames.insert(objc_opt::string_map::value_type(name, name_vmaddr));
2288 fClasses.insert(objc_opt::class_map::value_type(name, std::pair<uint64_t, uint64_t>(cls_vmaddr, hinfo_vmaddr)));
2289 fCount++;
2290 }
2291
2292 objc_opt::string_map& classNames() {
2293 return fClassNames;
2294 }
2295
2296 objc_opt::class_map& classes() {
2297 return fClasses;
2298 }
2299
2300 size_t count() const { return fCount; }
2301 };
2302
2303
2304 template <typename A>
2305 class ProtocolOptimizer
2306 {
2307 private:
2308 typedef typename A::P P;
2309 typedef typename A::P::uint_t pint_t;
2310
2311 objc_opt::string_map fProtocolNames;
2312 objc_opt::protocol_map fProtocols;
2313 size_t fProtocolCount;
2314 size_t fProtocolReferenceCount;
2315
2316 friend class ProtocolReferenceWalker<A, ProtocolOptimizer<A>>;
2317 pint_t visitProtocolReference(SharedCache<A>* cache, pint_t oldValue)
2318 {
2319 objc_protocol_t<A>* proto = (objc_protocol_t<A>*)
2320 cache->mappedAddressForVMAddress(oldValue);
2321 pint_t newValue = fProtocols[proto->getName(cache)];
2322 if (oldValue != newValue) fProtocolReferenceCount++;
2323 return newValue;
2324 }
2325
2326 public:
2327
2328 ProtocolOptimizer()
2329 : fProtocolNames()
2330 , fProtocols()
2331 , fProtocolCount(0)
2332 , fProtocolReferenceCount(0)
2333 { }
2334
2335 void addProtocols(SharedCache<A>* cache,
2336 const macho_header<P>* header)
2337 {
2338 PointerSection<A, objc_protocol_t<A> *>
2339 protocols(cache, header, "__DATA", "__objc_protolist");
2340
2341 for (pint_t i = 0; i < protocols.count(); i++) {
2342 objc_protocol_t<A> *proto = protocols.get(i);
2343
2344 const char *name = proto->getName(cache);
2345 if (fProtocolNames.count(name) == 0) {
2346 // Need a Swift demangler API in OS before we can handle this
2347 if (0 == strncmp(name, "_TtP", 4)) {
2348 throw "objc protocol has Swift name";
2349 }
2350 if (proto->getSize() > sizeof(objc_protocol_t<A>)) {
2351 throw "objc protocol is too big";
2352 }
2353
2354 uint64_t name_vmaddr = cache->VMAddressForMappedAddress(name);
2355 uint64_t proto_vmaddr = cache->VMAddressForMappedAddress(proto);
2356 fProtocolNames.insert(objc_opt::string_map::value_type(name, name_vmaddr));
2357 fProtocols.insert(objc_opt::protocol_map::value_type(name, proto_vmaddr));
2358 fProtocolCount++;
2359 }
2360 }
2361 }
2362
2363 const char *writeProtocols(SharedCache<A>* cache,
2364 uint8_t *& dest, size_t& remaining,
2365 std::vector<void*>& pointersInData,
2366 pint_t protocolClassVMAddr)
2367 {
2368 if (fProtocolCount == 0) return NULL;
2369
2370 if (protocolClassVMAddr == 0) {
2371 return "libobjc's Protocol class symbol not found (metadata not optimized)";
2372 }
2373
2374 size_t required = fProtocolCount * sizeof(objc_protocol_t<A>);
2375 if (remaining < required) {
2376 return "libobjc's read-write section is too small (metadata not optimized)";
2377 }
2378
2379 for (objc_opt::protocol_map::iterator iter = fProtocols.begin();
2380 iter != fProtocols.end();
2381 ++iter)
2382 {
2383 objc_protocol_t<A>* oldProto = (objc_protocol_t<A>*)
2384 cache->mappedAddressForVMAddress(iter->second);
2385
2386 // Create a new protocol object.
2387 objc_protocol_t<A>* proto = (objc_protocol_t<A>*)dest;
2388 dest += sizeof(*proto);
2389 remaining -= sizeof(*proto);
2390
2391 // Initialize it.
2392 uint32_t oldSize = oldProto->getSize();
2393 memcpy(proto, oldProto, oldSize);
2394 if (!proto->getIsaVMAddr()) {
2395 proto->setIsaVMAddr(protocolClassVMAddr);
2396 }
2397 if (oldSize < sizeof(*proto)) {
2398 // Protocol object is old. Populate new fields.
2399 proto->setSize(sizeof(objc_protocol_t<A>));
2400 // missing extendedMethodTypes is already nil
2401 }
2402 // Some protocol objects are big enough to have the
2403 // demangledName field but don't initialize it.
2404 if (! proto->getDemangledName(cache)) {
2405 proto->setDemangledName(cache, proto->getName(cache));
2406 }
2407 proto->setFixedUp();
2408
2409 // Redirect the protocol table at our new object.
2410 iter->second = cache->VMAddressForMappedAddress(proto);
2411
2412 // Add new rebase entries.
2413 proto->addPointers(pointersInData);
2414 }
2415
2416 return NULL;
2417 }
2418
2419 void updateReferences(SharedCache<A>* cache, const macho_header<P>* header)
2420 {
2421 ProtocolReferenceWalker<A, ProtocolOptimizer<A>> refs(*this);
2422 refs.walk(cache, header);
2423 }
2424
2425 objc_opt::string_map& protocolNames() {
2426 return fProtocolNames;
2427 }
2428
2429 objc_opt::protocol_map& protocols() {
2430 return fProtocols;
2431 }
2432
2433 size_t protocolCount() const { return fProtocolCount; }
2434 size_t protocolReferenceCount() const { return fProtocolReferenceCount; }
2435 };
2436
2437
2438 static int percent(size_t num, size_t denom) {
2439 if (denom) return (int)(num / (double)denom * 100);
2440 else return 100;
2441 }
2442
2443 template <typename A>
2444 void SharedCache<A>::optimizeObjC(std::vector<void*>& pointersInData)
2445 {
2446 const char *err;
2447
2448 if ( verbose ) {
2449 fprintf(stderr, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
2450 }
2451
2452 size_t headerSize = P::round_up(sizeof(objc_opt::objc_opt_t));
2453 if (headerSize != sizeof(objc_opt::objc_opt_t)) {
2454 warn(archName(), "libobjc's optimization structure size is wrong (metadata not optimized)");
2455 }
2456
2457 // Find libobjc's empty sections to fill in.
2458 // Find libobjc's list of pointers for us to use.
2459 const macho_section<P> *optROSection = NULL;
2460 const macho_section<P> *optRWSection = NULL;
2461 const macho_section<P> *optPointerListSection = NULL;
2462 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2463 if ( strstr(it->layout->getFilePath(), "/libobjc.") != NULL ) {
2464 const macho_header<P>* mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2465 optROSection = mh->getSection("__TEXT", "__objc_opt_ro");
2466 optRWSection = mh->getSection("__DATA", "__objc_opt_rw");
2467 optPointerListSection = mh->getSection("__DATA", "__objc_opt_ptrs");
2468 break;
2469 }
2470 }
2471
2472 if ( optROSection == NULL ) {
2473 warn(archName(), "libobjc's read-only section missing (metadata not optimized)");
2474 return;
2475 }
2476
2477 if ( optRWSection == NULL ) {
2478 warn(archName(), "libobjc's read/write section missing (metadata not optimized)");
2479 return;
2480 }
2481
2482 if ( optPointerListSection == NULL ) {
2483 warn(archName(), "libobjc's pointer list section missing (metadata not optimized)");
2484 return;
2485 }
2486
2487 uint8_t* optROData = (uint8_t*)mappedAddressForVMAddress(optROSection->addr());
2488 size_t optRORemaining = optROSection->size();
2489
2490 uint8_t* optRWData = (uint8_t*)mappedAddressForVMAddress(optRWSection->addr());
2491 size_t optRWRemaining = optRWSection->size();
2492
2493 if (optRORemaining < headerSize) {
2494 warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
2495 return;
2496 }
2497 objc_opt::objc_opt_t* optROHeader = (objc_opt::objc_opt_t *)optROData;
2498 optROData += headerSize;
2499 optRORemaining -= headerSize;
2500
2501 if (E::get32(optROHeader->version) != objc_opt::VERSION) {
2502 warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
2503 return;
2504 }
2505
2506 if (optPointerListSection->size() < sizeof(objc_opt::objc_opt_pointerlist_tt<pint_t>)) {
2507 warn(archName(), "libobjc's pointer list section is too small (metadata not optimized)");
2508 return;
2509 }
2510 const objc_opt::objc_opt_pointerlist_tt<pint_t> *optPointerList = (const objc_opt::objc_opt_pointerlist_tt<pint_t> *)mappedAddressForVMAddress(optPointerListSection->addr());
2511
2512 // Write nothing to optROHeader until everything else is written.
2513 // If something fails below, libobjc will not use the section.
2514
2515 // Find objc-containing dylibs
2516 std::vector<LayoutInfo> objcDylibs;
2517 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2518 macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2519 if (mh->getSection("__DATA", "__objc_imageinfo") || mh->getSegment("__OBJC")) {
2520 objcDylibs.push_back(*it);
2521 }
2522 }
2523
2524 // Build image list
2525
2526 // This is SAFE: the binaries themselves are unmodified.
2527
2528 std::vector<LayoutInfo> addressSortedDylibs = objcDylibs;
2529 std::sort(addressSortedDylibs.begin(), addressSortedDylibs.end(), ByAddressSorter());
2530
2531 uint64_t hinfoVMAddr = optRWSection->addr() + optRWSection->size() - optRWRemaining;
2532 HeaderInfoOptimizer<A> hinfoOptimizer;
2533 err = hinfoOptimizer.init(objcDylibs.size(), optRWData, optRWRemaining);
2534 if (err) {
2535 warn(archName(), err);
2536 return;
2537 }
2538 for(typename std::vector<LayoutInfo>::const_iterator it = addressSortedDylibs.begin(); it != addressSortedDylibs.end(); ++it) {
2539 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2540 hinfoOptimizer.update(this, mh, pointersInData);
2541 }
2542
2543
2544 // Update selector references and build selector list
2545
2546 // This is SAFE: if we run out of room for the selector table,
2547 // the modified binaries are still usable.
2548
2549 // Heuristic: choose selectors from libraries with more cstring data first.
2550 // This tries to localize selector cstring memory.
2551 ObjCSelectorUniquer<A> uniq(this);
2552 std::vector<LayoutInfo> sizeSortedDylibs = objcDylibs;
2553 std::sort(sizeSortedDylibs.begin(), sizeSortedDylibs.end(), ByCStringSectionSizeSorter());
2554
2555 SelectorOptimizer<A, ObjCSelectorUniquer<A> > selOptimizer(uniq);
2556 for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2557 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2558 LegacySelectorUpdater<A, ObjCSelectorUniquer<A> >::update(this, mh, uniq);
2559 selOptimizer.optimize(this, mh);
2560 }
2561
2562 uint64_t seloptVMAddr = optROSection->addr() + optROSection->size() - optRORemaining;
2563 objc_opt::objc_selopt_t *selopt = new(optROData) objc_opt::objc_selopt_t;
2564 err = selopt->write(seloptVMAddr, optRORemaining, uniq.strings());
2565 if (err) {
2566 warn(archName(), err);
2567 return;
2568 }
2569 optROData += selopt->size();
2570 optRORemaining -= selopt->size();
2571 selopt->byteswap(E::little_endian), selopt = NULL;
2572
2573
2574 // Build class table.
2575
2576 // This is SAFE: the binaries themselves are unmodified.
2577
2578 ClassListBuilder<A> classes(hinfoOptimizer);
2579 ClassWalker< A, ClassListBuilder<A> > classWalker(classes);
2580 for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2581 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2582 classWalker.walk(this, mh);
2583 }
2584
2585 uint64_t clsoptVMAddr = optROSection->addr() + optROSection->size() - optRORemaining;
2586 objc_opt::objc_clsopt_t *clsopt = new(optROData) objc_opt::objc_clsopt_t;
2587 err = clsopt->write(clsoptVMAddr, optRORemaining,
2588 classes.classNames(), classes.classes(), verbose);
2589 if (err) {
2590 warn(archName(), err);
2591 return;
2592 }
2593 optROData += clsopt->size();
2594 optRORemaining -= clsopt->size();
2595 size_t duplicateCount = clsopt->duplicateCount();
2596 clsopt->byteswap(E::little_endian), clsopt = NULL;
2597
2598
2599 // Sort method lists.
2600
2601 // This is SAFE: modified binaries are still usable as unsorted lists.
2602 // This must be done AFTER uniquing selectors.
2603
2604 MethodListSorter<A> methodSorter;
2605 for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2606 macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2607 methodSorter.optimize(this, mh);
2608 }
2609
2610
2611 // Unique protocols and build protocol table.
2612
2613 // This is SAFE: no protocol references are updated yet
2614 // This must be done AFTER updating method lists.
2615
2616 ProtocolOptimizer<A> protocolOptimizer;
2617 for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2618 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2619 protocolOptimizer.addProtocols(this, mh);
2620 }
2621
2622 pint_t protocolClassVMAddr = P::getP(optPointerList->protocolClass);
2623 err = protocolOptimizer.writeProtocols(this, optRWData, optRWRemaining,
2624 pointersInData, protocolClassVMAddr);
2625 if (err) {
2626 warn(archName(), err);
2627 return;
2628 }
2629
2630 uint64_t protocoloptVMAddr = optROSection->addr() + optROSection->size() - optRORemaining;
2631 objc_opt::objc_protocolopt_t *protocolopt = new(optROData) objc_opt::objc_protocolopt_t;
2632 err = protocolopt->write(protocoloptVMAddr, optRORemaining,
2633 protocolOptimizer.protocolNames(),
2634 protocolOptimizer.protocols(), verbose);
2635 if (err) {
2636 warn(archName(), err);
2637 return;
2638 }
2639 optROData += protocolopt->size();
2640 optRORemaining -= protocolopt->size();
2641 protocolopt->byteswap(E::little_endian), protocolopt = NULL;
2642
2643
2644 // Redirect protocol references to the uniqued protocols.
2645
2646 // This is SAFE: the new protocol objects are still usable as-is.
2647 for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2648 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2649 protocolOptimizer.updateReferences(this, mh);
2650 }
2651
2652
2653 // Repair ivar offsets.
2654
2655 // This is SAFE: the runtime always validates ivar offsets at runtime.
2656
2657 IvarOffsetOptimizer<A> ivarOffsetOptimizer;
2658 for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2659 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2660 ivarOffsetOptimizer.findGCClasses(this, mh);
2661 }
2662 for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2663 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2664 ivarOffsetOptimizer.optimize(this, mh);
2665 }
2666
2667
2668 // Success. Mark dylibs as optimized.
2669 for(typename std::vector<LayoutInfo>::const_iterator it = sizeSortedDylibs.begin(); it != sizeSortedDylibs.end(); ++it) {
2670 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
2671 const macho_section<P> *imageInfoSection;
2672 imageInfoSection = mh->getSection("__DATA", "__objc_imageinfo");
2673 if (!imageInfoSection) {
2674 imageInfoSection = mh->getSection("__OBJC", "__image_info");
2675 }
2676 if (imageInfoSection) {
2677 objc_image_info<A> *info = (objc_image_info<A> *)
2678 mappedAddressForVMAddress(imageInfoSection->addr());
2679 info->setOptimizedByDyld();
2680 }
2681 }
2682
2683
2684 // Success. Update RO header last.
2685 E::set32(optROHeader->selopt_offset, seloptVMAddr - optROSection->addr());
2686 E::set32(optROHeader->clsopt_offset, clsoptVMAddr - optROSection->addr());
2687 E::set32(optROHeader->protocolopt_offset, protocoloptVMAddr - optROSection->addr());
2688 E::set32(optROHeader->headeropt_offset, hinfoVMAddr - optROSection->addr());
2689
2690 if ( verbose ) {
2691 size_t roSize = optROSection->size() - optRORemaining;
2692 size_t rwSize = optRWSection->size() - optRWRemaining;
2693 fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2694 "(%d%%) used in libobjc read-only optimization section\n",
2695 archName(), roSize, optROSection->size(),
2696 percent(roSize, optROSection->size()));
2697 fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
2698 "(%d%%) used in libobjc read/write optimization section\n",
2699 archName(), rwSize, optRWSection->size(),
2700 percent(rwSize, optRWSection->size()));
2701 fprintf(stderr, "update_dyld_shared_cache: for %s, "
2702 "uniqued %zu selectors\n",
2703 archName(), uniq.strings().size());
2704 fprintf(stderr, "update_dyld_shared_cache: for %s, "
2705 "updated %zu selector references\n",
2706 archName(), uniq.count());
2707 fprintf(stderr, "update_dyld_shared_cache: for %s, "
2708 "uniqued %zu protocols\n",
2709 archName(), protocolOptimizer.protocolCount());
2710 fprintf(stderr, "update_dyld_shared_cache: for %s, "
2711 "updated %zu protocol references\n",
2712 archName(), protocolOptimizer.protocolReferenceCount());
2713 fprintf(stderr, "update_dyld_shared_cache: for %s, "
2714 "updated %zu ivar offsets\n",
2715 archName(), ivarOffsetOptimizer.optimized());
2716 fprintf(stderr, "update_dyld_shared_cache: for %s, "
2717 "sorted %zu method lists\n",
2718 archName(), methodSorter.optimized());
2719 fprintf(stderr, "update_dyld_shared_cache: for %s, "
2720 "recorded %zu classes (%zu duplicates)\n",
2721 archName(), classes.classNames().size(), duplicateCount);
2722 fprintf(stderr, "update_dyld_shared_cache: for %s, "
2723 "wrote objc metadata optimization version %d\n",
2724 archName(), objc_opt::VERSION);
2725 }
2726
2727 return;
2728 }
2729
2730
2731 static const char* sCleanupFile = NULL;
2732 static void cleanup(int sig)
2733 {
2734 ::signal(sig, SIG_DFL);
2735 if ( sCleanupFile != NULL )
2736 ::unlink(sCleanupFile);
2737 //if ( verbose )
2738 // fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
2739 if ( sig == SIGINT )
2740 ::exit(1);
2741 }
2742
2743
2744 // <rdar://problem/10730767> update_dyld_shared_cache should use sync_volume_np() instead of sync()
2745 static void sync_volume(const char* volumePath)
2746 {
2747 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
2748 int error = sync_volume_np(volumePath, SYNC_VOLUME_FULLSYNC|SYNC_VOLUME_FULLSYNC);
2749 #else
2750 int full_sync = 3; // SYNC_VOLUME_FULLSYNC | SYNC_VOLUME_FULLSYNC
2751 int error = 0;
2752 if ( fsctl(volumePath, 0x80004101 /*FSCTL_SYNC_VOLUME*/, &full_sync, 0) == -1)
2753 error = errno;
2754 #endif
2755 if ( error )
2756 ::sync();
2757 }
2758
2759
2760 // <rdar://problem/12552226> update shared cache should sign the shared cache
2761 static bool adhoc_codesign_share_cache(const char* path)
2762 {
2763 CFURLRef target = ::CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)path, strlen(path), FALSE);
2764 if ( target == NULL )
2765 return false;
2766
2767 SecStaticCodeRef code;
2768 OSStatus status = ::SecStaticCodeCreateWithPath(target, kSecCSDefaultFlags, &code);
2769 CFRelease(target);
2770 if ( status ) {
2771 ::fprintf(stderr, "codesign: failed to create url to signed object\n");
2772 return false;
2773 }
2774
2775 const void * keys[1] = { (void *)kSecCodeSignerIdentity } ;
2776 const void * values[1] = { (void *)kCFNull };
2777 CFDictionaryRef params = ::CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2778 if ( params == NULL ) {
2779 CFRelease(code);
2780 return false;
2781 }
2782
2783 SecCodeSignerRef signer;
2784 status = ::SecCodeSignerCreate(params, kSecCSDefaultFlags, &signer);
2785 CFRelease(params);
2786 if ( status ) {
2787 CFRelease(code);
2788 ::fprintf(stderr, "codesign: failed to create signer object\n");
2789 return false;
2790 }
2791
2792 status = ::SecCodeSignerAddSignatureWithErrors(signer, code, kSecCSDefaultFlags, NULL);
2793 CFRelease(code);
2794 CFRelease(signer);
2795 if ( status ) {
2796 ::fprintf(stderr, "codesign: failed to sign object: %s\n", path);
2797 return false;
2798 }
2799
2800 if ( verbose )
2801 ::fprintf(stderr, "codesigning complete of %s\n", path);
2802
2803 return true;
2804 }
2805
2806 template <typename A>
2807 void SharedCache<A>::writeCacheFile(const char *cacheFilePath, uint8_t *cacheFileBuffer, uint32_t cacheFileSize, bool deleteOldCache) {
2808 char tempCachePath[strlen(cacheFilePath)+16];
2809 sprintf(tempCachePath, "%s.tmp%u", cacheFilePath, getpid());
2810
2811 try {
2812 // install signal handlers to delete temp file if program is killed
2813 sCleanupFile = tempCachePath;
2814 ::signal(SIGINT, cleanup);
2815 ::signal(SIGBUS, cleanup);
2816 ::signal(SIGSEGV, cleanup);
2817
2818 // compute UUID of whole cache
2819 uint8_t digest[16];
2820 CC_MD5(cacheFileBuffer, cacheFileSize, digest);
2821 // <rdar://problem/6723729> uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
2822 digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
2823 digest[8] = ( digest[8] & 0x3F ) | 0x80;
2824 ((dyldCacheHeader<E>*)cacheFileBuffer)->set_uuid(digest);
2825
2826 // create var/db/dyld dirs if needed
2827 char dyldDirs[1024];
2828 strcpy(dyldDirs, cacheFilePath);
2829 char* lastSlash = strrchr(dyldDirs, '/');
2830 if ( lastSlash != NULL )
2831 lastSlash[1] = '\0';
2832 struct stat stat_buf;
2833 if ( stat(dyldDirs, &stat_buf) != 0 ) {
2834 const char* afterSlash = &dyldDirs[1];
2835 char* slash;
2836 while ( (slash = strchr(afterSlash, '/')) != NULL ) {
2837 *slash = '\0';
2838 ::mkdir(dyldDirs, S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
2839 *slash = '/';
2840 afterSlash = slash+1;
2841 }
2842 }
2843
2844 // create temp file for cache
2845 int fd = ::open(tempCachePath, O_CREAT | O_RDWR | O_TRUNC, 0644);
2846 if ( fd == -1 )
2847 throwf("can't create temp file %s, errno=%d", tempCachePath, errno);
2848
2849 // try to allocate whole cache file contiguously
2850 fstore_t fcntlSpec = { F_ALLOCATECONTIG|F_ALLOCATEALL, F_PEOFPOSMODE, 0, cacheFileSize, 0 };
2851 ::fcntl(fd, F_PREALLOCATE, &fcntlSpec);
2852
2853 // write out cache file
2854 if ( verbose )
2855 fprintf(stderr, "update_dyld_shared_cache: writing cache to disk: %s\n", tempCachePath);
2856 if ( ::pwrite(fd, cacheFileBuffer, cacheFileSize, 0) != cacheFileSize )
2857 throwf("write() failure creating cache file, errno=%d", errno);
2858
2859 // flush to disk and close
2860 int result = ::fcntl(fd, F_FULLFSYNC, NULL);
2861 if ( result == -1 )
2862 fprintf(stderr, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno, tempCachePath);
2863 result = ::close(fd);
2864 if ( result != 0 )
2865 fprintf(stderr, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno, tempCachePath);
2866
2867 if ( !iPhoneOS )
2868 adhoc_codesign_share_cache(tempCachePath);
2869
2870 if ( deleteOldCache ) {
2871 const char* pathLastSlash = strrchr(cacheFilePath, '/');
2872 if ( pathLastSlash != NULL ) {
2873 result = ::unlink(cacheFilePath);
2874 if ( result != 0 ) {
2875 if ( errno != ENOENT )
2876 fprintf(stderr, "update_dyld_shared_cache: warning, unable to remove existing cache %s because errno=%d\n", cacheFilePath, errno);
2877 }
2878 }
2879 }
2880
2881 // move new cache file to correct location for use after reboot
2882 if ( verbose )
2883 fprintf(stderr, "update_dyld_shared_cache: atomically moving cache file into place: %s\n", cacheFilePath);
2884 result = ::rename(tempCachePath, cacheFilePath);
2885 if ( result != 0 )
2886 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath, cacheFilePath, errno);
2887
2888 // flush everything to disk to assure rename() gets recorded
2889 sync_volume(cacheFilePath);
2890
2891 // restore default signal handlers
2892 ::signal(SIGINT, SIG_DFL);
2893 ::signal(SIGBUS, SIG_DFL);
2894 ::signal(SIGSEGV, SIG_DFL);
2895 }
2896 catch (...){
2897 // remove temp cache file
2898 ::unlink(tempCachePath);
2899 throw;
2900 }
2901 }
2902
2903
2904 template <> bool SharedCache<x86_64>::addCacheSlideInfo(){ return true; }
2905 template <> bool SharedCache<arm>::addCacheSlideInfo() { return true; }
2906 template <> bool SharedCache<x86>::addCacheSlideInfo() { return false; }
2907 template <> bool SharedCache<arm64>::addCacheSlideInfo() { return true; }
2908
2909
2910 template <typename A>
2911 bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst, int archIndex,
2912 int archCount, bool keepSignatures, bool dontMapLocalSymbols)
2913 {
2914 bool didUpdate = false;
2915 bool canEmitDevelopmentCache = true;
2916 char devCacheFilePath[strlen(fCacheFilePath)+strlen(".development")];
2917 char fileListFilePath[strlen(fCacheFilePath)+strlen(".list")];
2918 sprintf(devCacheFilePath, "%s.development", fCacheFilePath);
2919 sprintf(fileListFilePath, "%s.list", fCacheFilePath);
2920 std::vector<const char *> paths;
2921
2922 // already up to date?
2923 if ( force || fExistingIsNotUpToDate ) {
2924 if ( verbose )
2925 fprintf(stderr, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath);
2926 if ( fDylibs.size() == 0 ) {
2927 fprintf(stderr, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
2928 return false;
2929 }
2930 // delete existing cache while building the new one
2931 // this is a flag to dyld to stop pinging update_dyld_shared_cache
2932 if ( deleteExistingFirst )
2933 ::unlink(fCacheFilePath);
2934 uint8_t* inMemoryCache = NULL;
2935 uint32_t allocatedCacheSize = 0;
2936 try {
2937 // allocate a memory block to hold cache
2938 uint32_t cacheFileSize = 0;
2939 for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
2940 uint32_t end = it->sfm_file_offset + it->sfm_size;
2941 if ( end > cacheFileSize )
2942 cacheFileSize = end;
2943 }
2944 if ( vm_allocate(mach_task_self(), (vm_address_t*)(&inMemoryCache), cacheFileSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
2945 throwf("can't vm_allocate cache of size %u", cacheFileSize);
2946 allocatedCacheSize = cacheFileSize;
2947 fInMemoryCache = inMemoryCache;
2948
2949 // fill in header
2950 dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)inMemoryCache;
2951 const char* archPairName = fArchGraph->archName();
2952 char temp[16];
2953 strcpy(temp, "dyld_v1 ");
2954 strcpy(&temp[15-strlen(archPairName)], archPairName);
2955 header->set_magic(temp);
2956 //header->set_architecture(arch());
2957 header->set_mappingOffset(sizeof(dyldCacheHeader<E>));
2958 header->set_mappingCount(fMappings.size());
2959 header->set_imagesOffset(header->mappingOffset() + fMappings.size()*sizeof(dyldCacheFileMapping<E>));
2960 header->set_imagesCount(fDylibs.size()+fDylibAliases.size());
2961 header->set_dyldBaseAddress(fDyldBaseAddress);
2962 header->set_codeSignatureOffset(cacheFileSize);
2963 header->set_codeSignatureSize(0);
2964 header->set_slideInfoOffset(0);
2965 header->set_slideInfoSize(0);
2966 header->set_localSymbolsOffset(0);
2967 header->set_localSymbolsSize(0);
2968
2969 // fill in mappings
2970 dyldCacheFileMapping<E>* mapping = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
2971 for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
2972 if ( verbose )
2973 fprintf(stderr, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
2974 it->sfm_address, it->sfm_size, it->sfm_file_offset, it->sfm_init_prot);
2975 mapping->set_address(it->sfm_address);
2976 mapping->set_size(it->sfm_size);
2977 mapping->set_file_offset(it->sfm_file_offset);
2978 mapping->set_max_prot(it->sfm_max_prot);
2979 mapping->set_init_prot(it->sfm_init_prot);
2980 ++mapping;
2981 }
2982
2983 // fill in image table
2984 dyldCacheImageInfo<E>* image = (dyldCacheImageInfo<E>*)mapping;
2985 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2986 image->set_address(it->info.address);
2987 image->set_modTime(it->info.modTime);
2988 image->set_inode(it->info.inode);
2989 image->set_pathFileOffset(cacheFileOffsetForVMAddress(it->info.address+it->info.pathFileOffset));
2990 ++image;
2991 }
2992
2993 // add aliases to end of image table
2994 for(typename std::vector<LayoutInfo>::iterator it = fDylibAliases.begin(); it != fDylibAliases.end(); ++it) {
2995 image->set_address(it->info.address);
2996 image->set_modTime(it->info.modTime);
2997 image->set_inode(it->info.inode);
2998 image->set_pathFileOffset(it->info.pathFileOffset);
2999 strcpy((char*)inMemoryCache+it->info.pathFileOffset, it->aliases[0]);
3000 //fprintf(stderr, "adding alias to offset 0x%08X %s\n", it->info.pathFileOffset, it->aliases[0]);
3001 ++image;
3002 }
3003
3004 // copy each segment to cache buffer
3005 const int dylibCount = fDylibs.size();
3006 int dylibIndex = 0;
3007 int progressIndex = 0;
3008 bool foundLibSystem = false;
3009 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++dylibIndex) {
3010 const char* path = it->layout->getFilePath();
3011 int src = ::open(path, O_RDONLY, 0);
3012 if ( src == -1 )
3013 throwf("can't open file %s, errno=%d", it->layout->getID().name, errno);
3014 // mark source as "don't cache"
3015 (void)fcntl(src, F_NOCACHE, 1);
3016 // verify file has not changed since dependency analysis
3017 struct stat stat_buf;
3018 if ( fstat(src, &stat_buf) == -1)
3019 throwf("can't stat open file %s, errno=%d", path, errno);
3020 if ( (it->layout->getInode() != stat_buf.st_ino) )
3021 throwf("file inode changed from %llu to %llu during cache creation: %s", it->layout->getInode(), stat_buf.st_ino, path);
3022 else if ( it->layout->getLastModTime() != stat_buf.st_mtime )
3023 throwf("file mtime changed from 0x%lX to 0x%lX during cache creation: %s", it->layout->getLastModTime(), stat_buf.st_mtime, path);
3024 if ( strcmp(it->layout->getID().name, "/usr/lib/libSystem.B.dylib") == 0 )
3025 foundLibSystem = true;
3026 if ( verbose )
3027 fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getFilePath());
3028 try {
3029 const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
3030 for (int i=0; i < segs.size(); ++i) {
3031 const MachOLayoutAbstraction::Segment& seg = segs[i];
3032 if ( verbose ) {
3033 fprintf(stderr, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX, buffer address=%p\n",
3034 seg.name(), seg.size(), seg.newAddress(), &inMemoryCache[cacheFileOffsetForVMAddress(seg.newAddress())]);
3035 }
3036 if ( seg.size() > 0 ) {
3037 const uint64_t segmentSrcStartOffset = it->layout->getOffsetInUniversalFile()+seg.fileOffset();
3038 const uint64_t segmentSize = seg.fileSize();
3039 const uint64_t segmentDstStartOffset = cacheFileOffsetForVMAddress(seg.newAddress());
3040 ssize_t readResult = ::pread(src, &inMemoryCache[segmentDstStartOffset], segmentSize, segmentSrcStartOffset);
3041 if ( readResult != segmentSize ) {
3042 if ( readResult == -1 )
3043 throwf("read failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
3044 else
3045 throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
3046 segmentSize, segmentSrcStartOffset, readResult, it->layout->getID().name);
3047 }
3048 }
3049 }
3050 }
3051 catch (const char* msg) {
3052 throwf("%s while copying %s to shared cache", msg, it->layout->getID().name);
3053 }
3054 ::close(src);
3055 paths.push_back(it->layout->getID().name);
3056 if ( progress ) {
3057 // assuming read takes 40% of time
3058 int nextProgressIndex = archIndex*100+(40*dylibIndex)/dylibCount;
3059 if ( nextProgressIndex != progressIndex )
3060 fprintf(stdout, "%3u/%u\n", nextProgressIndex, archCount*100);
3061 progressIndex = nextProgressIndex;
3062 }
3063 }
3064 if ( !foundLibSystem )
3065 throw "cache would be missing required dylib /usr/lib/libSystem.B.dylib";
3066
3067 // set mapped address for each segment
3068 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
3069 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
3070 for (int i=0; i < segs.size(); ++i) {
3071 MachOLayoutAbstraction::Segment& seg = segs[i];
3072 if ( seg.size() > 0 )
3073 seg.setMappedAddress(inMemoryCache + cacheFileOffsetForVMAddress(seg.newAddress()));
3074 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
3075 }
3076 }
3077
3078 // also construct list of all pointers in cache to other things in cache
3079 std::vector<void*> pointersInData;
3080 pointersInData.reserve(1024);
3081
3082 // rebase each dylib in shared cache
3083 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
3084 try {
3085 Rebaser<A> r(*it->layout);
3086 if (!r.rebase(pointersInData)) {
3087 canEmitDevelopmentCache = false;
3088 fprintf(stderr, "update_dyld_shared_cache: Omitting development cache for %s, cannot rebase dylib into place for %s\n", archName(), it->layout->getID().name);
3089 }
3090 //if ( verbose )
3091 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
3092 }
3093 catch (const char* msg) {
3094 throwf("%s in %s", msg, it->layout->getID().name);
3095 }
3096 }
3097
3098 if ( verbose )
3099 fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs.size());
3100 // instantiate a Binder for each image and add to map
3101 typename Binder<A>::Map map;
3102 std::vector<Binder<A>*> binders;
3103 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
3104 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
3105 Binder<A>* binder = new Binder<A>(*it->layout);
3106 binders.push_back(binder);
3107 // only add dylibs to map
3108 if ( it->layout->getID().name != NULL )
3109 map[it->layout->getID().name] = binder;
3110 }
3111 // tell each Binder about the others
3112 for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
3113 (*it)->setDependentBinders(map);
3114 }
3115 // perform binding
3116 for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
3117 if ( verbose )
3118 fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it)->getDylibID());
3119 try {
3120 (*it)->bind(pointersInData);
3121 }
3122 catch (const char* msg) {
3123 throwf("%s in %s", msg, (*it)->getDylibID());
3124 }
3125 }
3126
3127 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
3128 const macho_header<P>* fHeader = (const macho_header<P>*)it->layout->getSegments()[0].mappedAddress();
3129 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
3130 const uint32_t cmd_count = fHeader->ncmds();
3131 const macho_load_command<P>* cmd = cmds;
3132 macho_dyld_info_command<P>* fDyldInfo;
3133 uint64_t originalLinkEditVMAddr = 0;
3134 for (uint32_t i = 0; i < cmd_count; ++i) {
3135 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
3136 macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
3137 if ( strcmp(seg->segname(), "__LINKEDIT") != 0 ) {
3138 pint_t oldFileOff = seg->fileoff();
3139 originalLinkEditVMAddr += seg->vmsize();
3140 // don't alter __TEXT until <rdar://problem/7022345> is fixed
3141 if ( strcmp(seg->segname(), "__TEXT") != 0 ) {
3142 // update all other segments fileoff to be offset from start of cache file
3143 seg->set_fileoff(cacheFileOffsetForVMAddress(seg->vmaddr()));
3144 }
3145 pint_t fileOffsetDelta = seg->fileoff() - oldFileOff;
3146 const MachOLayoutAbstraction::Segment* layoutSeg = it->layout->getSegment(seg->segname());
3147 if ( layoutSeg != NULL ) {
3148 seg->set_vmsize(layoutSeg->size());
3149 seg->set_filesize(layoutSeg->fileSize());
3150 }
3151 // update all sections in this segment
3152 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
3153 macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
3154 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
3155 if ( sect->offset() != 0 )
3156 sect->set_offset(sect->offset()+fileOffsetDelta);
3157 }
3158 }
3159 } else if (cmd->cmd() == LC_DYLD_INFO || cmd->cmd() == LC_DYLD_INFO_ONLY) {
3160 fDyldInfo = (macho_dyld_info_command<P>*)cmd;
3161 }
3162 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
3163 }
3164 }
3165
3166 // optimize binding
3167 for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
3168 try {
3169 (*it)->optimize();
3170 }
3171 catch (const char* msg) {
3172 throwf("%s in %s", msg, (*it)->getDylibID());
3173 }
3174 }
3175
3176 // delete binders
3177 for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
3178 delete *it;
3179 }
3180
3181 // merge/optimize all LINKEDIT segments
3182 if ( optimize ) {
3183 if ( verbose )
3184 fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
3185 cacheFileSize = (this->optimizeLINKEDIT(keepSignatures, dontMapLocalSymbols) - inMemoryCache);
3186 if ( verbose )
3187 fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
3188 // update header to reduce mapping size
3189 dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
3190 dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
3191 dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
3192 lastMapping->set_size(cacheFileSize-lastMapping->file_offset());
3193 // update fMappings so .map file will print correctly
3194 fMappings.back().sfm_size = cacheFileSize-fMappings.back().sfm_file_offset;
3195 // update header
3196 //fprintf(stderr, "update_dyld_shared_cache: changing end of cache address from 0x%08llX to 0x%08llX\n",
3197 // header->codeSignatureOffset(), fMappings.back().sfm_address + fMappings.back().sfm_size);
3198 header->set_codeSignatureOffset(fMappings.back().sfm_file_offset + fMappings.back().sfm_size);
3199 }
3200
3201 // dump dev cache with optimized linkedit, but not ObjC optimizations
3202 if (iPhoneOS && canEmitDevelopmentCache) {
3203 int fileListFD = ::open(fileListFilePath, O_WRONLY | O_CREAT | O_TRUNC, 0644);
3204 if ( fileListFD != -1 ) {
3205 for (const char* path : paths) {
3206 write(fileListFD, path, strlen(path)+1);
3207 write(fileListFD, "\n", 1);
3208 }
3209 close(fileListFD);
3210 }
3211
3212 ((dyldCacheHeader<E>*)inMemoryCache)->set_cacheType(1);
3213 writeCacheFile(devCacheFilePath, inMemoryCache, cacheFileSize, fCacheFileInFinalLocation);
3214 }
3215
3216 // unique objc selectors and update other objc metadata
3217 if ( optimize ) {
3218 optimizeObjC(pointersInData);
3219 if ( progress ) {
3220 // assuming objc optimizations takes 15% of time
3221 fprintf(stdout, "%3u/%u\n", (archIndex+1)*55, archCount*100);
3222 }
3223 }
3224
3225 if ( addCacheSlideInfo() ) {
3226 // build bitmap of which pointers need sliding
3227 uint8_t* const dataStart = &inMemoryCache[fMappings[1].sfm_file_offset]; // R/W mapping is always second
3228 uint8_t* const dataEnd = &inMemoryCache[fMappings[1].sfm_file_offset+fMappings[1].sfm_size];
3229 const int bitmapSize = (dataEnd - dataStart)/(4*8);
3230 uint8_t* bitmap = (uint8_t*)calloc(bitmapSize, 1);
3231 void* lastPointer = inMemoryCache;
3232 for(std::vector<void*>::iterator pit=pointersInData.begin(); pit != pointersInData.end(); ++pit) {
3233 if ( *pit != lastPointer ) {
3234 void* p = *pit;
3235 if ( (p < dataStart) || ( p > dataEnd) )
3236 throwf("DATA pointer for sliding, out of range 0x%08lX\n", (long)((uint8_t*)p-inMemoryCache));
3237 long offset = (long)((uint8_t*)p - dataStart);
3238 if ( (offset % 4) != 0 )
3239 throwf("pointer not 4-byte aligned in DATA offset 0x%08lX\n", offset);
3240 long byteIndex = offset / (4*8);
3241 long bitInByte = (offset % 32) >> 2;
3242 bitmap[byteIndex] |= (1 << bitInByte);
3243 lastPointer = p;
3244 }
3245 }
3246
3247 // allocate worst case size block of all slide info
3248 const int entry_size = 4096/(8*4); // 8 bits per byte, possible pointer every 4 bytes.
3249 const int toc_count = bitmapSize/entry_size;
3250 int slideInfoSize = sizeof(dyldCacheSlideInfo<E>) + 2*toc_count + entry_size*(toc_count+1);
3251 dyldCacheSlideInfo<E>* slideInfo = (dyldCacheSlideInfo<E>*)calloc(slideInfoSize, 1);
3252 slideInfo->set_version(1);
3253 slideInfo->set_toc_offset(sizeof(dyldCacheSlideInfo<E>));
3254 slideInfo->set_toc_count(toc_count);
3255 slideInfo->set_entries_offset((slideInfo->toc_offset()+2*toc_count+127)&(-128));
3256 slideInfo->set_entries_count(0);
3257 slideInfo->set_entries_size(entry_size);
3258 // append each unique entry
3259 const dyldCacheSlideInfoEntry* bitmapAsEntries = (dyldCacheSlideInfoEntry*)bitmap;
3260 dyldCacheSlideInfoEntry* const entriesInSlidInfo = (dyldCacheSlideInfoEntry*)((char*)slideInfo+slideInfo->entries_offset());
3261 int entry_count = 0;
3262 for (int i=0; i < toc_count; ++i) {
3263 const dyldCacheSlideInfoEntry* thisEntry = &bitmapAsEntries[i];
3264 // see if it is same as one already added
3265 bool found = false;
3266 for (int j=0; j < entry_count; ++j) {
3267 if ( memcmp(thisEntry, &entriesInSlidInfo[j], entry_size) == 0 ) {
3268 //fprintf(stderr, "toc[%d] optimized to %d\n", i, j);
3269 slideInfo->set_toc(i, j);
3270 found = true;
3271 break;
3272 }
3273 }
3274 if ( ! found ) {
3275 // append to end
3276 memcpy(&entriesInSlidInfo[entry_count], thisEntry, entry_size);
3277 slideInfo->set_toc(i, entry_count++);
3278 }
3279 }
3280 slideInfo->set_entries_count(entry_count);
3281
3282 int slideInfoPageSize = regionAlign(slideInfo->entries_offset() + entry_count*entry_size);
3283 cacheFileSize += slideInfoPageSize;
3284
3285 // update mappings to increase RO size
3286 dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
3287 dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
3288 dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
3289 lastMapping->set_size(lastMapping->size()+slideInfoPageSize);
3290
3291 // update header to show location of slidePointers
3292 cacheHeader->set_slideInfoOffset(cacheHeader->codeSignatureOffset());
3293 cacheHeader->set_slideInfoSize(slideInfoPageSize);
3294 cacheHeader->set_codeSignatureOffset(cacheHeader->codeSignatureOffset()+slideInfoPageSize);
3295
3296 // update fMappings so .map file will print correctly
3297 fMappings.back().sfm_size = cacheFileSize-fMappings.back().sfm_file_offset;
3298
3299 // copy compressed into into buffer
3300 memcpy(&inMemoryCache[cacheHeader->slideInfoOffset()], slideInfo, slideInfoPageSize);
3301 }
3302
3303 // append local symbol info in an unmapped region
3304 if ( dontMapLocalSymbols ) {
3305 uint32_t spaceAtEnd = allocatedCacheSize - cacheFileSize;
3306 uint32_t localSymbolsOffset = pageAlign(cacheFileSize);
3307 dyldCacheLocalSymbolsInfo<E>* infoHeader = (dyldCacheLocalSymbolsInfo<E>*)(&inMemoryCache[localSymbolsOffset]);
3308 const uint32_t entriesOffset = sizeof(dyldCacheLocalSymbolsInfo<E>);
3309 const uint32_t entriesCount = fLocalSymbolInfos.size();
3310 const uint32_t nlistOffset = entriesOffset + entriesCount * sizeof(dyldCacheLocalSymbolEntry<E>);
3311 const uint32_t nlistCount = fUnmappedLocalSymbols.size();
3312 const uint32_t stringsOffset = nlistOffset + nlistCount * sizeof(macho_nlist<P>);
3313 const uint32_t stringsSize = fUnmappedLocalsStringPool.size();
3314 if ( stringsOffset+stringsSize > spaceAtEnd )
3315 throwf("update_dyld_shared_cache[%u] for arch=%s, out of space for local symbols. Have 0x%X, Need 0x%X\n",
3316 getpid(), fArchGraph->archName(), spaceAtEnd, stringsOffset+stringsSize);
3317 // fill in local symbols info
3318 infoHeader->set_nlistOffset(nlistOffset);
3319 infoHeader->set_nlistCount(nlistCount);
3320 infoHeader->set_stringsOffset(stringsOffset);
3321 infoHeader->set_stringsSize(stringsSize);
3322 infoHeader->set_entriesOffset(entriesOffset);
3323 infoHeader->set_entriesCount(entriesCount);
3324 // copy info for each dylib
3325 dyldCacheLocalSymbolEntry<E>* entries = (dyldCacheLocalSymbolEntry<E>*)(&inMemoryCache[localSymbolsOffset+entriesOffset]);
3326 for (int i=0; i < entriesCount; ++i) {
3327 entries[i].set_dylibOffset(fLocalSymbolInfos[i].dylibOffset);
3328 entries[i].set_nlistStartIndex(fLocalSymbolInfos[i].nlistStartIndex);
3329 entries[i].set_nlistCount(fLocalSymbolInfos[i].nlistCount);
3330 }
3331 // copy nlists
3332 memcpy(&inMemoryCache[localSymbolsOffset+nlistOffset], &fUnmappedLocalSymbols[0], nlistCount*sizeof(macho_nlist<P>));
3333 // copy string pool
3334 memcpy(&inMemoryCache[localSymbolsOffset+stringsOffset], fUnmappedLocalsStringPool.getBuffer(), stringsSize);
3335
3336 // update state
3337 fUnmappedLocalSymbolsSize = pageAlign(stringsOffset + stringsSize);
3338 cacheFileSize = regionAlign(localSymbolsOffset + fUnmappedLocalSymbolsSize);
3339
3340 // update header to show location of slidePointers
3341 dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
3342 cacheHeader->set_localSymbolsOffset(localSymbolsOffset);
3343 cacheHeader->set_localSymbolsSize(stringsOffset+stringsSize);
3344 cacheHeader->set_codeSignatureOffset(cacheFileSize);
3345 }
3346
3347 // make sure after all optimizations, that whole cache file fits into shared region address range
3348 {
3349 dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
3350 dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[cacheHeader->mappingOffset()];
3351 // <rdar://problem/16128830> incorporate code signature size into overflow check
3352 uint32_t estCodeSigSize = regionAlign(cacheFileSize/200); // guess 0.5% for code signature
3353 for (int i=0; i < cacheHeader->mappingCount(); ++i) {
3354 uint64_t endAddr = mappings[i].address() + mappings[i].size() + estCodeSigSize;
3355 if ( endAddr > (sharedRegionStartAddress() + sharedRegionSize()) ) {
3356 throwf("update_dyld_shared_cache[%u] for arch=%s, shared cache will not fit in shared regions address space. Overflow amount: %lluKB\n",
3357 getpid(), fArchGraph->archName(), (endAddr-(sharedRegionStartAddress() + sharedRegionSize()))/1024);
3358 }
3359 }
3360 }
3361
3362 if ( fVerify ) {
3363 // if no existing cache, say so
3364 if ( fExistingCacheForVerification == NULL ) {
3365 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
3366 getpid(), archName());
3367 }
3368 // new cache is built, compare header entries
3369 const dyldCacheHeader<E>* newHeader = (dyldCacheHeader<E>*)inMemoryCache;
3370 const dyldCacheHeader<E>* oldHeader = (dyldCacheHeader<E>*)fExistingCacheForVerification;
3371 if ( newHeader->mappingCount() != oldHeader->mappingCount() ) {
3372 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
3373 getpid(), archName());
3374 }
3375 const dyldCacheFileMapping<E>* newMappings = (dyldCacheFileMapping<E>*)&inMemoryCache[newHeader->mappingOffset()];
3376 const dyldCacheFileMapping<E>* oldMappings = (dyldCacheFileMapping<E>*)&fExistingCacheForVerification[oldHeader->mappingOffset()];
3377 for (int i=0; i < newHeader->mappingCount(); ++i) {
3378 if ( newMappings[i].address() != oldMappings[i].address() ) {
3379 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d starts at a different address 0x%0llX vs 0x%0llX\n",
3380 getpid(), archName(), i, newMappings[i].address(), oldMappings[i].address() );
3381 }
3382 if ( newMappings[i].size() != oldMappings[i].size() ) {
3383 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
3384 getpid(), archName(), i);
3385 }
3386 }
3387
3388 //fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
3389 //fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
3390 // compare content to existing cache page by page
3391 for (int offset=0; offset < cacheFileSize; offset += 4096) {
3392 if ( memcmp(&inMemoryCache[offset], &fExistingCacheForVerification[offset], 4096) != 0 ) {
3393 fprintf(stderr, "verifier found differences on page offset 0x%08X for %s:\n", offset, archName());
3394 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++dylibIndex) {
3395 const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
3396 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator sit = segs.begin(); sit != segs.end(); ++sit) {
3397 const MachOLayoutAbstraction::Segment& seg = *sit;
3398 if ( (seg.mappedAddress() <= &inMemoryCache[offset]) && (&inMemoryCache[offset] < ((uint8_t*)seg.mappedAddress() + seg.fileSize())) ) {
3399 // all LINKEDITs point to the same region, so just print one
3400 if ( strcmp(seg.name(), "__LINKEDIT") == 0 )
3401 fprintf(stderr, " in merged LINKEDIT segment\n");
3402 else
3403 fprintf(stderr, " in segment %s of dylib %s\n", seg.name(), it->layout->getID().name);
3404 break;
3405 }
3406 }
3407 }
3408 for (int po=0; po < 4096; po += 16) {
3409 if ( memcmp(&inMemoryCache[offset+po], &fExistingCacheForVerification[offset+po], 16) != 0 ) {
3410 fprintf(stderr, " existing: 0x%08X: ", offset+po);
3411 for ( int j=0; j < 16; ++j)
3412 fprintf(stderr, " 0x%02X", fExistingCacheForVerification[offset+po+j]);
3413 fprintf(stderr, "\n");
3414 fprintf(stderr, " should be: 0x%08X: ", offset+po);
3415 for ( int j=0; j < 16; ++j)
3416 fprintf(stderr, " 0x%02X", inMemoryCache[offset+po+j]);
3417 fprintf(stderr, "\n");
3418 }
3419 }
3420 }
3421 }
3422 }
3423 else {
3424 ((dyldCacheHeader<E>*)inMemoryCache)->set_cacheType(0);
3425 writeCacheFile(fCacheFilePath, inMemoryCache, cacheFileSize, fCacheFileInFinalLocation);
3426 didUpdate = true;
3427 // generate human readable "map" file that shows the layout of the cache file
3428 if ( verbose )
3429 fprintf(stderr, "update_dyld_shared_cache: writing .map file to disk\n");
3430 char mapFilePath[strlen(fCacheFilePath)+16];
3431 sprintf(mapFilePath, "%s.map", fCacheFilePath);
3432 char tempMapFilePath[strlen(fCacheFilePath)+32];
3433 sprintf(tempMapFilePath, "%s.map%u", fCacheFilePath, getpid());
3434 FILE* fmap = ::fopen(tempMapFilePath, "w");
3435 if ( fmap == NULL ) {
3436 fprintf(stderr, "can't create map file %s, errno=%d", tempMapFilePath, errno);
3437 }
3438 else {
3439 for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
3440 const char* prot = "RW";
3441 if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_READ) )
3442 prot = "EX";
3443 else if ( it->sfm_init_prot == VM_PROT_READ )
3444 prot = "RO";
3445 else if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_WRITE|VM_PROT_READ) )
3446 prot = "WX";
3447 if ( it->sfm_size > 1024*1024 )
3448 fprintf(fmap, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/(1024*1024),
3449 it->sfm_address, it->sfm_address+it->sfm_size);
3450 else
3451 fprintf(fmap, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/1024,
3452 it->sfm_address, it->sfm_address+it->sfm_size);
3453 }
3454
3455 fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
3456 (fOffsetOfExportInfoInCombinedLinkedit-fOffsetOfWeakBindInfoInCombinedLinkedit)/1024,
3457 fLinkEditsStartAddress+fOffsetOfWeakBindInfoInCombinedLinkedit,
3458 fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit);
3459 fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
3460 (fOffsetOfBindInfoInCombinedLinkedit-fOffsetOfExportInfoInCombinedLinkedit)/1024,
3461 fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit,
3462 fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit);
3463 fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
3464 (fOffsetOfLazyBindInfoInCombinedLinkedit-fOffsetOfBindInfoInCombinedLinkedit)/1024,
3465 fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit,
3466 fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit);
3467 fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
3468 (fOffsetOfOldSymbolTableInfoInCombinedLinkedit-fOffsetOfLazyBindInfoInCombinedLinkedit)/1024,
3469 fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit,
3470 fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit);
3471 fprintf(fmap, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",
3472 (fSizeOfOldSymbolTableInfoInCombinedLinkedit)/(1024*1024),
3473 fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit,
3474 fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit+fSizeOfOldSymbolTableInfoInCombinedLinkedit);
3475 if ( fSizeOfFunctionStartsInCombinedLinkedit != 0 )
3476 fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",
3477 fSizeOfFunctionStartsInCombinedLinkedit/1024,
3478 fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit,
3479 fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit+fSizeOfFunctionStartsInCombinedLinkedit);
3480 if ( fSizeOfDataInCodeInCombinedLinkedit != 0 )
3481 fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld data-in-code info size\n",
3482 fSizeOfDataInCodeInCombinedLinkedit/1024,
3483 fLinkEditsStartAddress+fOffsetOfDataInCodeInCombinedLinkedit,
3484 fLinkEditsStartAddress+fOffsetOfDataInCodeInCombinedLinkedit+fSizeOfDataInCodeInCombinedLinkedit);
3485 if ( fSizeOfOldExternalRelocationsInCombinedLinkedit != 0 )
3486 fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",
3487 fSizeOfOldExternalRelocationsInCombinedLinkedit/1024,
3488 fLinkEditsStartAddress+fOffsetOfOldExternalRelocationsInCombinedLinkedit,
3489 fLinkEditsStartAddress+fOffsetOfOldExternalRelocationsInCombinedLinkedit+fSizeOfOldExternalRelocationsInCombinedLinkedit);
3490 fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld indirect symbol table size\n",
3491 fSizeOfOldIndirectSymbolsInCombinedLinkedit/1024,
3492 fLinkEditsStartAddress+fOffsetOfOldIndirectSymbolsInCombinedLinkedit,
3493 fLinkEditsStartAddress+fOffsetOfOldIndirectSymbolsInCombinedLinkedit+fSizeOfOldIndirectSymbolsInCombinedLinkedit);
3494 fprintf(fmap, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",
3495 (fSizeOfOldStringPoolInCombinedLinkedit)/(1024*1024),
3496 fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit,
3497 fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit+fSizeOfOldStringPoolInCombinedLinkedit);
3498
3499 dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
3500 if ( cacheHeader->slideInfoSize() != 0 ) {
3501 fprintf(fmap, " linkedit %4lluKB kernel slide info\n", (cacheHeader->slideInfoSize())/1024);
3502 }
3503
3504 fprintf(fmap, "unmapped -- %4uMB local symbol info\n", fUnmappedLocalSymbolsSize/(1024*1024));
3505
3506 uint64_t endMappingAddr = fMappings[2].sfm_address + fMappings[2].sfm_size;
3507 fprintf(fmap, "total map %4lluMB\n", (endMappingAddr - sharedRegionStartAddress())/(1024*1024));
3508 if ( sharedRegionStartWritableAddress(0) == 0x7FFF70000000LL ) {
3509 // x86_64 has different slide constraints
3510 uint64_t freeSpace = 256*1024*1024 - fMappings[1].sfm_size;
3511 fprintf(fmap, "r/w space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace/(1024*1024), (int)log2(freeSpace/4096));
3512 }
3513 else {
3514 uint64_t freeSpace = sharedRegionStartAddress() + sharedRegionSize() - endMappingAddr;
3515 fprintf(fmap, "free space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace/(1024*1024), (int)log2(freeSpace/4096));
3516 }
3517
3518 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
3519 fprintf(fmap, "%s\n", it->layout->getID().name);
3520 for (std::vector<const char*>::const_iterator ait = it->aliases.begin(); ait != it->aliases.end(); ++ait)
3521 fprintf(fmap, "%s\n", *ait);
3522 const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
3523 for (int i=0; i < segs.size(); ++i) {
3524 const MachOLayoutAbstraction::Segment& seg = segs[i];
3525 fprintf(fmap, "\t%16s 0x%0llX -> 0x%0llX\n", seg.name(), seg.newAddress(), seg.newAddress()+seg.size());
3526 }
3527 }
3528 if ( warnings.size() > 0 ) {
3529 fprintf(fmap, "# Warnings:\n");
3530 for (std::vector<const char*>::iterator it=warnings.begin(); it != warnings.end(); ++it) {
3531 fprintf(fmap, "# %s\n", *it);
3532 }
3533 }
3534 fclose(fmap);
3535 ::rename(tempMapFilePath, mapFilePath);
3536 }
3537 }
3538
3539 // free in memory cache
3540 vm_deallocate(mach_task_self(), (vm_address_t)inMemoryCache, allocatedCacheSize);
3541 inMemoryCache = NULL;
3542 if ( progress ) {
3543 // finished
3544 fprintf(stdout, "%3u/%u\n", (archIndex+1)*100, archCount*100);
3545 }
3546 }
3547 catch (...){
3548 // remove in memory cache
3549 if ( inMemoryCache != NULL )
3550 vm_deallocate(mach_task_self(), (vm_address_t)inMemoryCache, allocatedCacheSize);
3551 throw;
3552 }
3553 }
3554 return didUpdate;
3555 }
3556
3557
3558
3559 //
3560 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
3561 // the paths used to search for dylibs that should go in the shared cache
3562 //
3563 // Leading and trailing white space is ignored
3564 // Blank lines are ignored
3565 // Lines starting with # are ignored
3566 //
3567 static void parsePathsFile(const char* filePath, std::vector<const char*>& paths)
3568 {
3569 // read in whole file
3570 int fd = open(filePath, O_RDONLY, 0);
3571 if ( fd == -1 ) {
3572 fprintf(stderr, "update_dyld_shared_cache: can't open file: %s\n", filePath);
3573 exit(1);
3574 }
3575 struct stat stat_buf;
3576 fstat(fd, &stat_buf);
3577 char* p = (char*)malloc(stat_buf.st_size);
3578 if ( p == NULL ) {
3579 fprintf(stderr, "update_dyld_shared_cache: malloc failure\n");
3580 exit(1);
3581 }
3582 if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) {
3583 fprintf(stderr, "update_dyld_shared_cache: can't read file: %s\n", filePath);
3584 exit(1);
3585 }
3586 ::close(fd);
3587
3588 // parse into paths and add to vector
3589 char * const end = &p[stat_buf.st_size];
3590 enum { lineStart, inSymbol, inComment } state = lineStart;
3591 char* symbolStart = NULL;
3592 for (char* s = p; s < end; ++s ) {
3593 switch ( state ) {
3594 case lineStart:
3595 if ( *s =='#' ) {
3596 state = inComment;
3597 }
3598 else if ( !isspace(*s) ) {
3599 state = inSymbol;
3600 symbolStart = s;
3601 }
3602 break;
3603 case inSymbol:
3604 if ( *s == '\n' ) {
3605 *s = '\0';
3606 // removing any trailing spaces
3607 char* last = s-1;
3608 while ( isspace(*last) ) {
3609 *last = '\0';
3610 --last;
3611 }
3612 paths.push_back(symbolStart);
3613 symbolStart = NULL;
3614 state = lineStart;
3615 }
3616 break;
3617 case inComment:
3618 if ( *s == '\n' )
3619 state = lineStart;
3620 break;
3621 }
3622 }
3623 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
3624 }
3625
3626
3627
3628 static void setSharedDylibs(const char* rootPath, const std::vector<const char*>& overlayPaths, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
3629 {
3630 // set file system root
3631 ArchGraph::setFileSystemRoot(rootPath);
3632 ArchGraph::setFileSystemOverlay(overlayPaths);
3633
3634 // initialize all architectures requested
3635 for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
3636 ArchGraph::addArchPair(*a);
3637
3638 // add roots to graph
3639 for(std::vector<const char*>::const_iterator it = rootsPaths.begin(); it != rootsPaths.end(); ++it)
3640 ArchGraph::addRoot(*it, onlyArchs);
3641
3642 // determine shared dylibs
3643 for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
3644 ArchGraph::findSharedDylibs(*a);
3645 }
3646
3647
3648 static void scanForSharedDylibs(const char* rootPath, const std::vector<const char*>& overlayPaths, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
3649 {
3650 char rootDirOfPathFiles[strlen(rootPath)+strlen(dirOfPathFiles)+2];
3651 // in -root mode, look for roots in /rootpath/var/db/dyld
3652 if ( rootPath[0] != '\0' ) {
3653 strcpy(rootDirOfPathFiles, rootPath);
3654 strcat(rootDirOfPathFiles, dirOfPathFiles);
3655 dirOfPathFiles = rootDirOfPathFiles;
3656 }
3657
3658 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
3659 if ( verbose )
3660 fprintf(stderr, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles);
3661 std::vector<const char*> rootsPaths;
3662 DIR* dir = ::opendir(dirOfPathFiles);
3663 if ( dir == NULL )
3664 throwf("%s does not exist, errno=%d\n", dirOfPathFiles, errno);
3665 for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
3666 if ( entry->d_type == DT_REG || entry->d_type == DT_UNKNOWN ) {
3667 // only look at regular files ending in .paths
3668 if ( strcmp(&entry->d_name[entry->d_namlen-6], ".paths") == 0 ) {
3669 struct stat tmpStatPathsFile;
3670 char fullPath[strlen(dirOfPathFiles)+entry->d_namlen+2];
3671 strcpy(fullPath, dirOfPathFiles);
3672 strcat(fullPath, "/");
3673 strcat(fullPath, entry->d_name);
3674 if ( lstat(fullPath, &tmpStatPathsFile) == -1 ) {
3675 fprintf(stderr, "update_dyld_shared_cache: can't access %s\n", fullPath);
3676 }
3677 else if ( S_ISREG(tmpStatPathsFile.st_mode) ) {
3678 parsePathsFile(fullPath, rootsPaths);
3679 }
3680 else {
3681 fprintf(stderr, "update_dyld_shared_cache: wrong file type for %s\n", fullPath);
3682 }
3683 }
3684 else {
3685 fprintf(stderr, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry->d_name);
3686 }
3687 }
3688 }
3689 ::closedir(dir);
3690
3691 if ( rootsPaths.size() == 0 )
3692 fprintf(stderr, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
3693 setSharedDylibs(rootPath, overlayPaths, onlyArchs, rootsPaths);
3694 }
3695
3696 static void setSharedDylibs(const char* rootPath, const std::vector<const char*>& overlayPaths, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
3697 {
3698 std::vector<const char*> rootsPaths;
3699 parsePathsFile(pathsFile, rootsPaths);
3700 setSharedDylibs(rootPath, overlayPaths, onlyArchs, rootsPaths);
3701 }
3702
3703
3704 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
3705 // could leave large half written cache files laying around. The function deletes
3706 // those files. To prevent the deletion of tmp files being created by another
3707 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
3708 // creation time was before the last restart of this machine.
3709 static void deleteOrphanTempCacheFiles()
3710 {
3711 DIR* dir = ::opendir(MACOSX_DYLD_SHARED_CACHE_DIR);
3712 if ( dir != NULL ) {
3713 std::vector<const char*> filesToDelete;
3714 for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
3715 if ( entry->d_type == DT_REG ) {
3716 // only look at files with .tmp in name
3717 if ( strstr(entry->d_name, ".tmp") != NULL ) {
3718 char fullPath[strlen(MACOSX_DYLD_SHARED_CACHE_DIR)+entry->d_namlen+2];
3719 strcpy(fullPath, MACOSX_DYLD_SHARED_CACHE_DIR);
3720 strcat(fullPath, "/");
3721 strcat(fullPath, entry->d_name);
3722 struct stat tmpFileStatInfo;
3723 if ( stat(fullPath, &tmpFileStatInfo) != -1 ) {
3724 int mib[2] = {CTL_KERN, KERN_BOOTTIME};
3725 struct timeval boottime;
3726 size_t size = sizeof(boottime);
3727 if ( (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) && (boottime.tv_sec != 0) ) {
3728 // make sure this file is older than the boot time of this machine
3729 if ( tmpFileStatInfo.st_mtime < boottime.tv_sec ) {
3730 filesToDelete.push_back(strdup(fullPath));
3731 }
3732 }
3733 }
3734 }
3735 }
3736 }
3737 ::closedir(dir);
3738 for(std::vector<const char*>::iterator it = filesToDelete.begin(); it != filesToDelete.end(); ++it) {
3739 fprintf(stderr, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it);
3740 ::unlink(*it);
3741 }
3742 }
3743 }
3744
3745
3746
3747 static bool updateSharedeCacheFile(const char* rootPath, const std::vector<const char*>& overlayPaths, const char* cacheDir, bool explicitCacheDir, const std::set<ArchPair>& onlyArchs,
3748 bool force, bool alphaSort, bool optimize, bool deleteExistingFirst, bool verify, bool keepSignatures, bool dontMapLocalSymbols)
3749 {
3750 bool didUpdate = false;
3751 // get dyld load address info
3752 UniversalMachOLayout* dyldLayout = NULL;
3753 char dyldPath[1024];
3754 strlcpy(dyldPath, rootPath, 1024);
3755 strlcat(dyldPath, "/usr/lib/dyld", 1024);
3756 struct stat stat_buf;
3757 if ( stat(dyldPath, &stat_buf) == 0 ) {
3758 dyldLayout = new UniversalMachOLayout(dyldPath, &onlyArchs);
3759 }
3760 else {
3761 dyldLayout = new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs);
3762 }
3763 const int archCount = onlyArchs.size();
3764 int index = 0;
3765 for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a, ++index) {
3766 const MachOLayoutAbstraction* dyldLayoutForArch = dyldLayout->getSlice(*a);
3767 uint64_t dyldBaseAddress = 0;
3768 if ( dyldLayoutForArch != NULL )
3769 dyldBaseAddress = dyldLayoutForArch->getBaseAddress();
3770 else
3771 fprintf(stderr, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
3772 switch ( a->arch ) {
3773 case CPU_TYPE_I386:
3774 {
3775 SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
3776 didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
3777 }
3778 break;
3779 case CPU_TYPE_X86_64:
3780 {
3781 SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
3782 didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
3783 }
3784 break;
3785 case CPU_TYPE_ARM:
3786 {
3787 SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
3788 didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
3789 }
3790 break;
3791 case CPU_TYPE_ARM64:
3792 {
3793 SharedCache<arm64> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
3794 didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
3795 }
3796 break;
3797 }
3798 }
3799
3800 if ( !iPhoneOS )
3801 deleteOrphanTempCacheFiles();
3802
3803 return didUpdate;
3804 }
3805
3806
3807 static void usage()
3808 {
3809 fprintf(stderr, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
3810 }
3811
3812
3813 int main(int argc, const char* argv[])
3814 {
3815 std::set<ArchPair> onlyArchs;
3816 const char* rootPath = "";
3817 std::vector<const char*> overlayPaths;
3818 const char* dylibListFile = NULL;
3819 bool force = false;
3820 bool alphaSort = false;
3821 bool optimize = true;
3822 bool verify = false;
3823 bool keepSignatures = false;
3824 bool explicitCacheDir = false;
3825 bool dontMapLocalSymbols = false;
3826 bool relaunchForHaswell = false;
3827 const char* cacheDir = NULL;
3828
3829 try {
3830 // parse command line options
3831 for(int i=1; i < argc; ++i) {
3832 const char* arg = argv[i];
3833 if ( arg[0] == '-' ) {
3834 if ( strcmp(arg, "-debug") == 0 ) {
3835 verbose = true;
3836 }
3837 else if ( strcmp(arg, "-force") == 0 ) {
3838 force = true;
3839 }
3840 else if ( strcmp(arg, "-verify") == 0 ) {
3841 verify = true;
3842 }
3843 else if ( strcmp(arg, "-sort_by_name") == 0 ) {
3844 alphaSort = true;
3845 }
3846 else if ( strcmp(arg, "-progress") == 0 ) {
3847 progress = true;
3848 }
3849 else if ( strcmp(arg, "-opt") == 0 ) {
3850 optimize = true;
3851 }
3852 else if ( strcmp(arg, "-no_opt") == 0 ) {
3853 optimize = false;
3854 }
3855 else if ( strcmp(arg, "-dont_map_local_symbols") == 0 ) {
3856 dontMapLocalSymbols = true;
3857 }
3858 else if ( strcmp(arg, "-iPhone") == 0 ) {
3859 iPhoneOS = true;
3860 alphaSort = true;
3861 }
3862 else if ( strcmp(arg, "-dylib_list") == 0 ) {
3863 dylibListFile = argv[++i];
3864 if ( dylibListFile == NULL )
3865 throw "-dylib_list missing path argument";
3866 }
3867 else if ( (strcmp(arg, "-root") == 0) || (strcmp(arg, "--root") == 0) ) {
3868 rootPath = argv[++i];
3869 if ( rootPath == NULL )
3870 throw "-root missing path argument";
3871 }
3872 else if ( strcmp(arg, "-overlay") == 0 ) {
3873 const char* path = argv[++i];
3874 if ( path == NULL )
3875 throw "-overlay missing path argument";
3876 overlayPaths.push_back(path);
3877 }
3878 else if ( strcmp(arg, "-cache_dir") == 0 ) {
3879 cacheDir = argv[++i];
3880 if ( cacheDir == NULL )
3881 throw "-cache_dir missing path argument";
3882 explicitCacheDir = true;
3883 }
3884 else if ( strcmp(arg, "-arch") == 0 ) {
3885 const char* arch = argv[++i];
3886 if ( strcmp(arch, "i386") == 0 )
3887 onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
3888 else if ( strcmp(arch, "x86_64") == 0 )
3889 onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
3890 else if ( strcmp(arch, "x86_64h") == 0 )
3891 onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H));
3892 else if ( strcmp(arch, "armv4t") == 0 )
3893 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V4T));
3894 else if ( strcmp(arch, "armv5") == 0 )
3895 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V5TEJ));
3896 else if ( strcmp(arch, "armv6") == 0 )
3897 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6));
3898 else if ( strcmp(arch, "armv7") == 0 )
3899 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7));
3900 else if ( strcmp(arch, "armv7f") == 0 )
3901 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7F));
3902 else if ( strcmp(arch, "armv7k") == 0 )
3903 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K));
3904 else if ( strcmp(arch, "armv7s") == 0 )
3905 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S));
3906 else if ( strcmp(arch, "arm64") == 0 )
3907 onlyArchs.insert(ArchPair(CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL));
3908 else
3909 throwf("unknown architecture %s", arch);
3910 }
3911 else if ( strcmp(arg, "-universal_boot") == 0 ) {
3912 onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
3913 onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
3914 relaunchForHaswell = true;
3915 }
3916 else {
3917 usage();
3918 throwf("unknown option: %s\n", arg);
3919 }
3920 }
3921 else {
3922 usage();
3923 throwf("unknown option: %s\n", arg);
3924 }
3925 }
3926
3927 // strip tailing slashes on -root
3928 // make it a real path so as to not make all dylibs look like symlink aliases
3929 if ( rootPath[0] != '\0' ) {
3930 char realRootPath[MAXPATHLEN];
3931 if ( realpath(rootPath, realRootPath) == NULL )
3932 throwf("realpath() failed on %s\n", rootPath);
3933 rootPath = strdup(realRootPath);
3934 }
3935
3936 // strip tailing slashes on -overlay
3937 for (std::vector<const char*>::iterator it=overlayPaths.begin(); it != overlayPaths.end(); ++it) {
3938 char realOverlayPath[MAXPATHLEN];
3939 if ( realpath(*it, realOverlayPath) == NULL )
3940 throwf("realpath() failed on %s\n", *it);
3941 *it = strdup(realOverlayPath);
3942 }
3943
3944 // set default location to write cache dir
3945 if ( cacheDir == NULL )
3946 cacheDir = (iPhoneOS ? IPHONE_DYLD_SHARED_CACHE_DIR : MACOSX_DYLD_SHARED_CACHE_DIR);
3947
3948 // if no restrictions specified, use architectures that work on this machine
3949 if ( onlyArchs.size() == 0 ) {
3950 if ( iPhoneOS ) {
3951 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6));
3952 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7));
3953 }
3954 else {
3955 int available;
3956 size_t len = sizeof(int);
3957 #if __i386__ || __x86_64__
3958 onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
3959 // check system is capable of running 64-bit programs
3960 if ( (sysctlbyname("hw.optional.x86_64", &available, &len, NULL, 0) == 0) && available ) {
3961 // check system is capable of running x86_64h code
3962 struct host_basic_info info;
3963 mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
3964 mach_port_t hostPort = mach_host_self();
3965 kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
3966 mach_port_deallocate(mach_task_self(), hostPort);
3967 if ( result != KERN_SUCCESS )
3968 throw "host_info() failed";
3969 if ( info.cpu_subtype == CPU_SUBTYPE_X86_64_H )
3970 onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H));
3971 else
3972 onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_ALL));
3973 }
3974 #else
3975 #error unsupported architecture
3976 #endif
3977 }
3978 }
3979
3980 if ( !verify && (geteuid() != 0) )
3981 throw "you must be root to run this tool";
3982
3983 // build list of shared dylibs
3984 if ( dylibListFile != NULL )
3985 setSharedDylibs(rootPath, overlayPaths, dylibListFile, onlyArchs);
3986 else
3987 scanForSharedDylibs(rootPath, overlayPaths, "/var/db/dyld/shared_region_roots/", onlyArchs);
3988 bool didUpdate = updateSharedeCacheFile(rootPath, overlayPaths, cacheDir, explicitCacheDir, onlyArchs, force, alphaSort, optimize,
3989 false, verify, keepSignatures, dontMapLocalSymbols);
3990
3991 if ( didUpdate && !iPhoneOS ) {
3992 void* handle = dlopen("/usr/lib/libspindump.dylib", RTLD_LAZY);
3993 if ( handle != NULL ) {
3994 typedef bool (*dscsym_proc_t)(const char *root);
3995 dscsym_proc_t proc = (dscsym_proc_t)dlsym(handle, "dscsym_save_nuggets_for_current_caches");
3996 const char* nuggetRootPath = "/";
3997 if ( !overlayPaths.empty() )
3998 nuggetRootPath = overlayPaths[0];
3999 else if ( rootPath[0] != '\0' )
4000 nuggetRootPath = rootPath;
4001 (*proc)(nuggetRootPath);
4002 }
4003 dlclose(handle);
4004 }
4005
4006 if ( relaunchForHaswell ) {
4007 char cmd[2048];
4008 strlcpy(cmd, argv[0], 2048);
4009 strlcat(cmd, " -arch x86_64h", 2048);
4010 if ( force )
4011 strlcat(cmd, " -force", 2048);
4012 if ( verify )
4013 strlcat(cmd, " -verify", 2048);
4014 if ( alphaSort )
4015 strlcat(cmd, " -sort_by_name", 2048);
4016 if ( (rootPath != NULL) && (rootPath[0] != '\0') ) {
4017 strlcat(cmd, " -root ", 2048);
4018 strlcat(cmd, rootPath, 2048);
4019 }
4020 return system(cmd);
4021 }
4022
4023 }
4024 catch (const char* msg) {
4025 fprintf(stderr, "update_dyld_shared_cache failed: %s\n", msg);
4026 return 1;
4027 }
4028
4029 return 0;
4030 }
4031
4032
4033