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