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