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