]> git.saurik.com Git - apple/dyld.git/blob - launch-cache/update_dyld_shared_cache.cpp
704aa81c133c9168b5ce72ac1d92e7139ae2ee9b
[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-2009 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 #include <vproc.h>
48 #include <vproc_priv.h>
49
50 #include "dyld_cache_format.h"
51
52 #include <vector>
53 #include <set>
54 #include <map>
55 #include <ext/hash_map>
56
57 #include "Architectures.hpp"
58 #include "MachOLayout.hpp"
59 #include "MachORebaser.hpp"
60 #include "MachOBinder.hpp"
61 #include "CacheFileAbstraction.hpp"
62
63 #define SELOPT_WRITE
64 #include <objc/objc-selopt.h>
65
66
67 static bool verbose = false;
68 static bool progress = false;
69 static std::vector<const char*> warnings;
70
71
72 static void warn(const char *arch, const char *format, ...)
73 {
74 char *msg;
75
76 va_list args;
77 va_start(args, format);
78 ::vasprintf(&msg, format, args);
79 va_end(args);
80
81 warnings.push_back(msg);
82
83 if ( verbose ) {
84 ::fprintf(::stderr, "update_dyld_shared_cache: warning: %s%s%s%s\n",
85 arch ? "for arch " : "",
86 arch ? arch : "",
87 arch ? ", " : "",
88 msg);
89 }
90 }
91
92
93 static uint64_t pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
94
95 class ArchGraph
96 {
97 public:
98 static void addArchPair(ArchPair ap);
99 static void addRoot(const char* vpath, const std::set<ArchPair>& archs);
100 static void findSharedDylibs(ArchPair ap);
101 static ArchGraph* graphForArchPair(ArchPair ap) { return fgPerArchGraph[ap]; }
102 static void setFileSystemRoot(const char* root, bool usesOverlay) { fgFileSystemRoot = root; fgUsesOverlay = usesOverlay; }
103 static const char* archName(ArchPair ap);
104
105 ArchPair getArchPair() { return fArchPair; }
106 std::set<const class MachOLayoutAbstraction*>& getSharedDylibs() { return fSharedDylibs; }
107 const char* archName() { return archName(fArchPair); }
108
109 private:
110
111 class DependencyNode
112 {
113 public:
114 DependencyNode(ArchGraph*, const char* path, const MachOLayoutAbstraction* layout);
115 void loadDependencies(const MachOLayoutAbstraction*);
116 void markNeededByRoot(DependencyNode*);
117 const char* getPath() const { return fPath; }
118 const MachOLayoutAbstraction* getLayout() const { return fLayout; }
119 size_t useCount() const { return fRootsDependentOnThis.size(); }
120 bool allDependentsFound() const { return !fDependentMissing; }
121 private:
122 ArchGraph* fGraph;
123 const char* fPath;
124 const MachOLayoutAbstraction* fLayout;
125 bool fDependenciesLoaded;
126 bool fDependentMissing;
127 std::set<DependencyNode*> fDependsOn;
128 std::set<DependencyNode*> fRootsDependentOnThis;
129 };
130
131 struct CStringEquals {
132 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
133 };
134 typedef __gnu_cxx::hash_map<const char*, class DependencyNode*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
135
136
137 ArchGraph(ArchPair ap) : fArchPair(ap) {}
138 void addRoot(const char* path, const MachOLayoutAbstraction*);
139 DependencyNode* getNode(const char* path);
140 DependencyNode* getNodeForVirtualPath(const char* vpath);
141 static bool canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap);
142
143 static std::map<ArchPair, ArchGraph*> fgPerArchGraph;
144 static const char* fgFileSystemRoot;
145 static bool fgUsesOverlay;
146
147 ArchPair fArchPair;
148 std::set<DependencyNode*> fRoots;
149 PathToNode fNodes;
150 std::set<const MachOLayoutAbstraction*> fSharedDylibs; // use set to avoid duplicates when installname!=realpath
151 };
152 std::map<ArchPair, ArchGraph*> ArchGraph::fgPerArchGraph;
153 const char* ArchGraph::fgFileSystemRoot = "";
154 bool ArchGraph::fgUsesOverlay = false;
155
156 void ArchGraph::addArchPair(ArchPair ap)
157 {
158 //fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
159 fgPerArchGraph[ap] = new ArchGraph(ap);
160 }
161
162 void ArchGraph::addRoot(const char* vpath, const std::set<ArchPair>& onlyArchs)
163 {
164 char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
165 const char* path = NULL;
166 if ( strlen(fgFileSystemRoot) == 0 ) {
167 path = vpath;
168 }
169 else {
170 strcpy(completePath, fgFileSystemRoot);
171 strcat(completePath, vpath); // assumes vpath starts with '/'
172 if ( fgUsesOverlay ) {
173 // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
174 struct stat stat_buf;
175 if ( stat(completePath, &stat_buf) == 0 )
176 path = completePath;
177 else
178 path = vpath;
179 }
180 else {
181 // using -root means alway redirect /usr/lib to /rootpath/usr/lib
182 path = completePath;
183 }
184 }
185 try {
186 const UniversalMachOLayout& uni = UniversalMachOLayout::find(path, &onlyArchs);
187 for(std::set<ArchPair>::iterator ait = onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
188 try {
189 const MachOLayoutAbstraction* layout = uni.getSlice(*ait);
190 fgPerArchGraph[*ait]->addRoot(path, layout);
191 }
192 catch (const char* msg) {
193 if ( verbose )
194 fprintf(stderr, "update_dyld_shared_cache: warning for %s can't use root %s: %s\n", fgPerArchGraph[*ait]->archName(), path, msg);
195 }
196
197 }
198 }
199 catch (const char* msg) {
200 fprintf(stderr, "update_dyld_shared_cache: warning can't use root %s: %s\n", path, msg);
201 }
202 }
203
204
205
206 void ArchGraph::addRoot(const char* path, const MachOLayoutAbstraction* layout)
207 {
208 if ( verbose )
209 fprintf(stderr, "update_dyld_shared_cache: adding root: %s\n", path);
210 DependencyNode* node = this->getNode(path);
211 fRoots.insert(node);
212 const MachOLayoutAbstraction* mainExecutableLayout = NULL;
213 if ( layout->getFileType() == MH_EXECUTE )
214 mainExecutableLayout = layout;
215 node->loadDependencies(mainExecutableLayout);
216 node->markNeededByRoot(node);
217 if ( layout->getFileType() == MH_DYLIB )
218 node->markNeededByRoot(NULL);
219 }
220
221 // a virtual path does not have the fgFileSystemRoot prefix
222 ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
223 {
224 if ( fgFileSystemRoot == NULL ) {
225 return this->getNode(vpath);
226 }
227 else {
228 char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
229 strcpy(completePath, fgFileSystemRoot);
230 strcat(completePath, vpath); // assumes vpath starts with '/'
231 if ( fgUsesOverlay ) {
232 // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
233 struct stat stat_buf;
234 if ( stat(completePath, &stat_buf) == 0 )
235 return this->getNode(completePath);
236 else
237 return this->getNode(vpath);
238 }
239 else {
240 // using -root means always use /rootpath/usr/lib
241 return this->getNode(completePath);
242 }
243 }
244 }
245
246 ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
247 {
248 // look up supplied path to see if node already exists
249 PathToNode::iterator pos = fNodes.find(path);
250 if ( pos != fNodes.end() )
251 return pos->second;
252
253 // get real path
254 char realPath[MAXPATHLEN];
255 if ( realpath(path, realPath) == NULL )
256 throwf("realpath() failed on %s\n", path);
257
258 // look up real path to see if node already exists
259 pos = fNodes.find(realPath);
260 if ( pos != fNodes.end() )
261 return pos->second;
262
263 // still does not exist, so create a new node
264 const UniversalMachOLayout& uni = UniversalMachOLayout::find(realPath);
265 DependencyNode* node = new DependencyNode(this, realPath, uni.getSlice(fArchPair));
266 if ( node->getLayout() == NULL ) {
267 throwf("%s is missing arch %s", realPath, archName(fArchPair));
268 }
269 // add realpath to node map
270 fNodes[node->getPath()] = node;
271 // if install name is not real path, add install name to node map
272 if ( (node->getLayout()->getFileType() == MH_DYLIB) && (strcmp(realPath, node->getLayout()->getID().name) != 0) ) {
273 //fprintf(stderr, "adding node alias 0x%08X %s for %s\n", fArch, node->getLayout()->getID().name, realPath);
274 fNodes[node->getLayout()->getID().name] = node;
275 }
276 return node;
277 }
278
279
280 void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction* mainExecutableLayout)
281 {
282 if ( !fDependenciesLoaded ) {
283 fDependenciesLoaded = true;
284 // add dependencies
285 const std::vector<MachOLayoutAbstraction::Library>& dependsOn = fLayout->getLibraries();
286 for(std::vector<MachOLayoutAbstraction::Library>::const_iterator it = dependsOn.begin(); it != dependsOn.end(); ++it) {
287 try {
288 const char* dependentPath = it->name;
289 if ( strncmp(dependentPath, "@executable_path/", 17) == 0 ) {
290 if ( mainExecutableLayout == NULL )
291 throw "@executable_path without main executable";
292 // expand @executable_path path prefix
293 const char* executablePath = mainExecutableLayout->getFilePath();
294 char newPath[strlen(executablePath) + strlen(dependentPath)+2];
295 strcpy(newPath, executablePath);
296 char* addPoint = strrchr(newPath,'/');
297 if ( addPoint != NULL )
298 strcpy(&addPoint[1], &dependentPath[17]);
299 else
300 strcpy(newPath, &dependentPath[17]);
301 dependentPath = strdup(newPath);
302 }
303 else if ( strncmp(dependentPath, "@loader_path/", 13) == 0 ) {
304 // expand @loader_path path prefix
305 char newPath[strlen(fPath) + strlen(dependentPath)+2];
306 strcpy(newPath, fPath);
307 char* addPoint = strrchr(newPath,'/');
308 if ( addPoint != NULL )
309 strcpy(&addPoint[1], &dependentPath[13]);
310 else
311 strcpy(newPath, &dependentPath[13]);
312 dependentPath = strdup(newPath);
313 }
314 else if ( strncmp(dependentPath, "@rpath/", 7) == 0 ) {
315 throw "@rpath not supported in dyld shared cache";
316 }
317 fDependsOn.insert(fGraph->getNodeForVirtualPath(dependentPath));
318 }
319 catch (const char* msg) {
320 if ( it->weakImport && ! fLayout->hasSplitSegInfo() ) {
321 // ok to ignore missing weak imported dylibs from things that are
322 // not going to be in the dyld shared cache
323 }
324 else {
325 fprintf(stderr, "warning, could not bind %s because %s\n", fPath, msg);
326 fDependentMissing = true;
327 }
328 }
329 }
330 // recurse
331 for(std::set<DependencyNode*>::iterator it = fDependsOn.begin(); it != fDependsOn.end(); ++it) {
332 (*it)->loadDependencies(mainExecutableLayout);
333 }
334 }
335 }
336
337 void ArchGraph::DependencyNode::markNeededByRoot(ArchGraph::DependencyNode* rootNode)
338 {
339 if ( fRootsDependentOnThis.count(rootNode) == 0 ) {
340 fRootsDependentOnThis.insert(rootNode);
341 for(std::set<DependencyNode*>::iterator it = fDependsOn.begin(); it != fDependsOn.end(); ++it) {
342 (*it)->markNeededByRoot(rootNode);
343 }
344 }
345 }
346
347
348 ArchGraph::DependencyNode::DependencyNode(ArchGraph* graph, const char* path, const MachOLayoutAbstraction* layout)
349 : fGraph(graph), fPath(strdup(path)), fLayout(layout), fDependenciesLoaded(false), fDependentMissing(false)
350 {
351 //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
352 }
353
354 void ArchGraph::findSharedDylibs(ArchPair ap)
355 {
356 const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
357 std::set<const MachOLayoutAbstraction*> possibleLibs;
358 //fprintf(stderr, "shared for arch 0x%08X\n", arch);
359 for(PathToNode::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
360 DependencyNode* node = it->second;
361 // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
362 if ( node->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
363 const MachOLayoutAbstraction* layout = node->getLayout();
364 if ( layout->hasSplitSegInfo() && layout->isRootOwned() && layout->inSharableLocation() )
365 possibleLibs.insert(layout);
366 //fprintf(stderr, "\t%s\n", it->first);
367 }
368 }
369
370 // prune so that all shareable libs depend only on other shareable libs
371 std::set<const MachOLayoutAbstraction*>& sharedLibs = fgPerArchGraph[ap]->fSharedDylibs;
372 std::map<const MachOLayoutAbstraction*,bool> shareableMap;
373 for (std::set<const MachOLayoutAbstraction*>::iterator lit = possibleLibs.begin(); lit != possibleLibs.end(); ++lit) {
374 if ( canBeShared(*lit, ap, possibleLibs, shareableMap) )
375 sharedLibs.insert(*lit);
376 }
377 }
378
379 const char* ArchGraph::archName(ArchPair ap)
380 {
381 switch ( ap.arch ) {
382 case CPU_TYPE_POWERPC:
383 return "ppc";
384 case CPU_TYPE_I386:
385 return "i386";
386 case CPU_TYPE_X86_64:
387 return "x86_64";
388 case CPU_TYPE_ARM:
389 switch ( ap.subtype ) {
390 case CPU_SUBTYPE_ARM_V4T:
391 return "armv4t";
392 case CPU_SUBTYPE_ARM_V6:
393 return "armv6";
394 case CPU_SUBTYPE_ARM_V5TEJ:
395 return "armv5";
396 case CPU_SUBTYPE_ARM_XSCALE:
397 return "arm-xscale";
398 case CPU_SUBTYPE_ARM_V7:
399 return "armv7";
400 default:
401 return "arm";
402 }
403 default:
404 return "unknown";
405 }
406 }
407
408 bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap)
409 {
410 // check map which is a cache of results
411 std::map<const MachOLayoutAbstraction*, bool>::iterator mapPos = shareableMap.find(layout);
412 if ( mapPos != shareableMap.end() ) {
413 return mapPos->second;
414 }
415 // see if possible
416 if ( possibleLibs.count(layout) == 0 ) {
417 shareableMap[layout] = false;
418 char* msg;
419 if ( ! layout->hasSplitSegInfo() )
420 asprintf(&msg, "can't put %s in shared cache because it was not built for 10.5 or later", layout->getID().name);
421 else if ( ! layout->isRootOwned() )
422 asprintf(&msg, "can't put %s in shared cache because it is not owned by root", layout->getID().name);
423 else if ( ! layout->inSharableLocation() )
424 asprintf(&msg, "can't put %s in shared cache because it is not in /usr/lib or /System/Library", layout->getID().name);
425 else
426 asprintf(&msg, "can't put %s in shared cache", layout->getID().name);
427 warnings.push_back(msg);
428 if ( verbose )
429 fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
430 return false;
431 }
432 // look recursively
433 shareableMap[layout] = true; // mark this shareable early in case of circular references
434 const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
435 const std::vector<MachOLayoutAbstraction::Library>& dependents = layout->getLibraries();
436 for (std::vector<MachOLayoutAbstraction::Library>::const_iterator dit = dependents.begin(); dit != dependents.end(); ++dit) {
437 PathToNode::const_iterator pos = nodes.find(dit->name);
438 if ( pos == nodes.end() ) {
439 // path from load command does not match any loaded dylibs, maybe there is a temp symlink
440 char realPath[MAXPATHLEN];
441 if ( realpath(dit->name, realPath) != NULL ) {
442 if ( nodes.find(realPath) != nodes.end() )
443 continue;
444 }
445 shareableMap[layout] = false;
446 char* msg;
447 asprintf(&msg, "can't put %s in shared cache because it depends on %s which can't be found", layout->getID().name, dit->name);
448 warnings.push_back(msg);
449 if ( verbose )
450 fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
451 return false;
452 }
453 else {
454 if ( ! canBeShared(pos->second->getLayout(), ap, possibleLibs, shareableMap) ) {
455 shareableMap[layout] = false;
456 char* msg;
457 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);
458 warnings.push_back(msg);
459 if ( verbose )
460 fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
461 return false;
462 }
463 }
464 }
465 return true;
466 }
467
468
469 template <typename A>
470 class SharedCache
471 {
472 public:
473 SharedCache(ArchGraph* graph, const char* rootPath, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress);
474 bool update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex,
475 int archCount, bool keepSignatures);
476 static const char* cacheFileSuffix(bool optimized, const char* archName);
477
478 uint64_t mappedCacheAddressForAddress(uint64_t addr);
479
480 private:
481 typedef typename A::P P;
482 typedef typename A::P::E E;
483 typedef typename A::P::uint_t pint_t;
484
485 bool notUpToDate(const char* path);
486 bool notUpToDate(const void* cache);
487 uint8_t* optimizeLINKEDIT(bool keepSignatures);
488 void optimizeObjC();
489
490 static void getSharedCacheBasAddresses(cpu_type_t arch, uint64_t* baseReadOnly, uint64_t* baseWritable);
491 static cpu_type_t arch();
492 static const char* archName();
493 static uint64_t sharedRegionReadOnlyStartAddress();
494 static uint64_t sharedRegionWritableStartAddress();
495 static uint64_t sharedRegionReadOnlySize();
496 static uint64_t sharedRegionWritableSize();
497 static uint64_t getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide);
498
499
500 void assignNewBaseAddresses();
501 uint64_t cacheFileOffsetForAddress(uint64_t addr);
502
503 struct LayoutInfo {
504 const MachOLayoutAbstraction* layout;
505 dyld_cache_image_info info;
506 };
507
508 struct ByNameSorter {
509 bool operator()(const LayoutInfo& left, const LayoutInfo& right)
510 { return (strcmp(left.layout->getID().name, right.layout->getID().name) < 0); }
511 };
512
513 struct ByCStringSectionSizeSorter {
514 bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
515 const std::vector<MachOLayoutAbstraction::Segment>& segs_l =
516 left.layout->getSegments();
517 const std::vector<MachOLayoutAbstraction::Segment>& segs_r =
518 right.layout->getSegments();
519 if (segs_l.size() == 0 || segs_r.size() == 0) {
520 // one image has no segments
521 return segs_l.size() > segs_r.size();
522 }
523 const macho_header<P> *mh_l = (const macho_header<P>*)segs_l[0].mappedAddress();
524 const macho_header<P> *mh_r = (const macho_header<P>*)segs_r[0].mappedAddress();
525 const macho_section<P> *cstring_l = mh_l->getSection("__TEXT", "__cstring");
526 const macho_section<P> *cstring_r = mh_r->getSection("__TEXT", "__cstring");
527 if (!cstring_l || !cstring_r) {
528 // one image has no cstrings
529 return cstring_l && !cstring_r;
530 }
531
532 return cstring_l->size() > cstring_r->size();
533 }
534 };
535
536 struct Sorter {
537 Sorter(std::map<const MachOLayoutAbstraction*, uint32_t>& map): fMap(map) {}
538 bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
539 return (fMap[left.layout] < fMap[right.layout]);
540 }
541 private:
542 std::map<const MachOLayoutAbstraction*, uint32_t>& fMap;
543 };
544
545
546 ArchGraph* fArchGraph;
547 const bool fVerify;
548 bool fExistingIsNotUpToDate;
549 const char* fCacheFilePath;
550 uint8_t* fExistingCacheForVerification;
551 std::vector<LayoutInfo> fDylibs;
552 std::vector<shared_file_mapping_np> fMappings;
553 uint32_t fHeaderSize;
554 uint8_t* fInMemoryCache;
555 uint64_t fDyldBaseAddress;
556 uint64_t fLinkEditsTotalUnoptimizedSize;
557 uint64_t fLinkEditsStartAddress;
558 MachOLayoutAbstraction::Segment* fFirstLinkEditSegment;
559 uint32_t fOffsetOfBindInfoInCombinedLinkedit;
560 uint32_t fOffsetOfWeakBindInfoInCombinedLinkedit;
561 uint32_t fOffsetOfLazyBindInfoInCombinedLinkedit;
562 uint32_t fOffsetOfExportInfoInCombinedLinkedit;
563 uint32_t fOffsetOfOldSymbolTableInfoInCombinedLinkedit;
564 uint32_t fLinkEditsTotalOptimizedSize;
565 };
566
567
568 // Access a section containing a list of pointers
569 template <typename A, typename T>
570 class PointerSection
571 {
572 typedef typename A::P P;
573 typedef typename A::P::uint_t pint_t;
574
575 SharedCache<A>* const fCache;
576 const macho_section<P>* const fSection;
577 pint_t * const fBase;
578 uint64_t const fCount;
579
580 public:
581 PointerSection(SharedCache<A>* cache, const macho_header<P>* header,
582 const char *segname, const char *sectname)
583 : fCache(cache)
584 , fSection(header->getSection(segname, sectname))
585 , fBase(fSection ? (pint_t *)cache->mappedCacheAddressForAddress(fSection->addr()) : 0)
586 , fCount(fSection ? fSection->size() / sizeof(pint_t) : 0)
587 {
588 }
589
590 uint64_t count() const { return fCount; }
591
592 uint64_t getUnmapped(uint64_t index) const {
593 if (index >= fCount) throwf("index out of range");
594 return P::getP(fBase[index]);
595 }
596
597 T get(uint64_t index) const {
598 return (T)fCache->mappedCacheAddressForAddress(getUnmapped(index));
599 }
600
601 void set(uint64_t index, uint64_t value) {
602 if (index >= fCount) throwf("index out of range");
603 P::setP(fBase[index], value);
604 }
605 };
606
607 // Access a section containing an array of structures
608 template <typename A, typename T>
609 class ArraySection
610 {
611 typedef typename A::P P;
612
613 SharedCache<A>* const fCache;
614 const macho_section<P>* const fSection;
615 T * const fBase;
616 uint64_t const fCount;
617
618 public:
619 ArraySection(SharedCache<A>* cache, const macho_header<P>* header,
620 const char *segname, const char *sectname)
621 : fCache(cache)
622 , fSection(header->getSection(segname, sectname))
623 , fBase(fSection ? (T *)cache->mappedCacheAddressForAddress(fSection->addr()) : 0)
624 , fCount(fSection ? fSection->size() / sizeof(T) : 0)
625 {
626 }
627
628 uint64_t count() const { return fCount; }
629
630 T& get(uint64_t index) const {
631 if (index >= fCount) throwf("index out of range");
632 return fBase[index];
633 }
634 };
635
636
637 // GrP fixme
638 #include "ObjCLegacyAbstraction.hpp"
639 #include "ObjCModernAbstraction.hpp"
640
641
642
643 template <> cpu_type_t SharedCache<ppc>::arch() { return CPU_TYPE_POWERPC; }
644 template <> cpu_type_t SharedCache<x86>::arch() { return CPU_TYPE_I386; }
645 template <> cpu_type_t SharedCache<x86_64>::arch() { return CPU_TYPE_X86_64; }
646 template <> cpu_type_t SharedCache<arm>::arch() { return CPU_TYPE_ARM; }
647
648 template <> uint64_t SharedCache<ppc>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
649 template <> uint64_t SharedCache<x86>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
650 template <> uint64_t SharedCache<x86_64>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL; }
651 template <> uint64_t SharedCache<arm>::sharedRegionReadOnlyStartAddress() { return 0x30000000; }
652
653 template <> uint64_t SharedCache<ppc>::sharedRegionWritableStartAddress() { return 0xA0000000; }
654 template <> uint64_t SharedCache<x86>::sharedRegionWritableStartAddress() { return 0xA0000000; }
655 template <> uint64_t SharedCache<x86_64>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL; }
656 template <> uint64_t SharedCache<arm>::sharedRegionWritableStartAddress() { return 0x38000000; }
657
658 template <> uint64_t SharedCache<ppc>::sharedRegionReadOnlySize() { return 0x10000000; }
659 template <> uint64_t SharedCache<x86>::sharedRegionReadOnlySize() { return 0x10000000; }
660 template <> uint64_t SharedCache<x86_64>::sharedRegionReadOnlySize() { return 0x7FE00000; }
661 template <> uint64_t SharedCache<arm>::sharedRegionReadOnlySize() { return 0x08000000; }
662
663 template <> uint64_t SharedCache<ppc>::sharedRegionWritableSize() { return 0x10000000; }
664 template <> uint64_t SharedCache<x86>::sharedRegionWritableSize() { return 0x10000000; }
665 template <> uint64_t SharedCache<x86_64>::sharedRegionWritableSize() { return 0x20000000; }
666 template <> uint64_t SharedCache<arm>::sharedRegionWritableSize() { return 0x08000000; }
667
668
669 template <> const char* SharedCache<ppc>::archName() { return "ppc"; }
670 template <> const char* SharedCache<x86>::archName() { return "i386"; }
671 template <> const char* SharedCache<x86_64>::archName() { return "x86_64"; }
672 template <> const char* SharedCache<arm>::archName() { return "arm"; }
673
674 template <> const char* SharedCache<ppc>::cacheFileSuffix(bool optimized, const char*) { return optimized ? "ppc" : "rosetta"; }
675 template <> const char* SharedCache<x86>::cacheFileSuffix(bool, const char* archName) { return archName; }
676 template <> const char* SharedCache<x86_64>::cacheFileSuffix(bool, const char* archName){ return archName; }
677 template <> const char* SharedCache<arm>::cacheFileSuffix(bool, const char* archName) { return archName; }
678
679 template <typename A>
680 SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress)
681 : fArchGraph(graph), fVerify(verify), fExistingIsNotUpToDate(true), fCacheFilePath(NULL),
682 fExistingCacheForVerification(NULL), fDyldBaseAddress(dyldBaseAddress)
683 {
684 if ( fArchGraph->getArchPair().arch != arch() )
685 throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph->getArchPair().arch, arch());
686
687 // build vector of all shared dylibs
688 std::set<const MachOLayoutAbstraction*>& dylibs = fArchGraph->getSharedDylibs();
689 for(std::set<const MachOLayoutAbstraction*>::iterator it = dylibs.begin(); it != dylibs.end(); ++it) {
690 const MachOLayoutAbstraction* lib = *it;
691 LayoutInfo temp;
692 temp.layout = lib;
693 temp.info.address = 0;
694 temp.info.modTime = lib->getLastModTime();
695 temp.info.inode = lib->getInode();
696 temp.info.pathFileOffset = lib->getNameFileOffset();
697 fDylibs.push_back(temp);
698 }
699
700 // examine the existing shared cache file
701 char cachePath[1024];
702 strcpy(cachePath, rootPath);
703 strcat(cachePath, DYLD_SHARED_CACHE_DIR);
704 strcat(cachePath, DYLD_SHARED_CACHE_BASE_NAME);
705 strcat(cachePath, cacheFileSuffix(optimize, fArchGraph->archName()));
706 fCacheFilePath = strdup(cachePath);
707 const char* pathToExistingCacheFile = fCacheFilePath;
708 char cachePathNonOverlay[1024];
709 if ( overlay ) {
710 strcpy(cachePathNonOverlay, DYLD_SHARED_CACHE_DIR);
711 strcat(cachePathNonOverlay, DYLD_SHARED_CACHE_BASE_NAME);
712 strcat(cachePathNonOverlay, cacheFileSuffix(optimize, fArchGraph->archName()));
713 pathToExistingCacheFile = cachePathNonOverlay;
714 }
715 fExistingIsNotUpToDate = this->notUpToDate(pathToExistingCacheFile);
716
717 // sort shared dylibs
718 if ( verify ) {
719 // already sorted by notUpToDate()
720 }
721 else if ( alphaSort ) {
722 std::sort(fDylibs.begin(), fDylibs.end(), ByNameSorter());
723 }
724 else {
725 // random sort for Address Space Randomization
726 std::map<const MachOLayoutAbstraction*, uint32_t> map;
727 for(typename std::vector<struct LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it)
728 map[it->layout] = arc4random();
729 std::sort(fDylibs.begin(), fDylibs.end(), Sorter(map));
730 }
731
732 // assign segments in each dylib a new address
733 this->assignNewBaseAddresses();
734
735 // check that cache we are about to create for verification purposes has same layout as existing cache
736 if ( verify ) {
737 // if no existing cache, say so
738 if ( fExistingCacheForVerification == NULL ) {
739 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
740 getpid(), archName());
741 }
742 const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)fExistingCacheForVerification;
743 const dyldCacheImageInfo<E>* cacheEntry = (dyldCacheImageInfo<E>*)(fExistingCacheForVerification + header->imagesOffset());
744 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++cacheEntry) {
745 if ( cacheEntry->address() != it->layout->getSegments()[0].newAddress() ) {
746 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",
747 getpid(), archName(), it->layout->getID().name, cacheEntry->address(), it->layout->getSegments()[0].newAddress());
748 }
749 }
750 }
751
752 // calculate cache file header size
753 fHeaderSize = pageAlign(sizeof(dyld_cache_header)
754 + fMappings.size()*sizeof(shared_file_mapping_np)
755 + fDylibs.size()*sizeof(dyld_cache_image_info) );
756 //+ fDependencyPool.size()*sizeof(uint16_t));
757
758 if ( fHeaderSize > 0x3000 )
759 throwf("header size miscalculation 0x%08X", fHeaderSize);
760 }
761
762
763 template <typename A>
764 uint64_t SharedCache<A>::getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide)
765 {
766 return proposedNewAddress;
767 }
768
769 template <>
770 uint64_t SharedCache<ppc>::getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide)
771 {
772 // for ppc writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
773 return (((executableSlide & 0x000000000000F000ULL) - ((proposedNewAddress - originalAddress) & 0x000000000000F000ULL)) & 0x000000000000F000ULL) + proposedNewAddress;
774 }
775
776
777 template <typename A>
778 void SharedCache<A>::assignNewBaseAddresses()
779 {
780 // first layout TEXT and DATA for split-seg (or can be split-seg) dylibs
781 uint64_t currentExecuteAddress = sharedRegionReadOnlyStartAddress() + 0x3000;
782 uint64_t currentWritableAddress = sharedRegionWritableStartAddress();
783 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
784 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
785 MachOLayoutAbstraction::Segment* executableSegment = NULL;
786 for (int i=0; i < segs.size(); ++i) {
787 MachOLayoutAbstraction::Segment& seg = segs[i];
788 seg.reset();
789 if ( seg.writable() ) {
790 if ( seg.executable() && it->layout->hasSplitSegInfo() ) {
791 // skip __IMPORT segments in this pass
792 }
793 else {
794 // __DATA segment
795 // for ppc, writable segments have to move in 64K increments
796 if ( it->layout->hasSplitSegInfo() ) {
797 if ( executableSegment == NULL )
798 throwf("first segment in dylib is not executable for %s", it->layout->getID().name);
799 seg.setNewAddress(getWritableSegmentNewAddress(currentWritableAddress, seg.address(), executableSegment->newAddress() - executableSegment->address()));
800 }
801 else
802 seg.setNewAddress(currentWritableAddress);
803 currentWritableAddress = pageAlign(seg.newAddress() + seg.size());
804 }
805 }
806 else {
807 if ( seg.executable() ) {
808 // __TEXT segment
809 if ( it->info.address == 0 )
810 it->info.address = currentExecuteAddress;
811 executableSegment = &seg;
812 seg.setNewAddress(currentExecuteAddress);
813 currentExecuteAddress += pageAlign(seg.size());
814 }
815 else {
816 // skip read-only segments in this pass
817 }
818 }
819 }
820 }
821
822 // append all read-only (but not LINKEDIT) segments at end of all TEXT segments
823 // append all IMPORT segments at end of all DATA segments rounded to next 2MB
824 uint64_t currentReadOnlyAddress = currentExecuteAddress;
825 uint64_t startWritableExecutableAddress = (currentWritableAddress + 0x200000 - 1) & (-0x200000);
826 uint64_t currentWritableExecutableAddress = startWritableExecutableAddress;
827 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
828 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
829 for(int i=0; i < segs.size(); ++i) {
830 MachOLayoutAbstraction::Segment& seg = segs[i];
831 if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") != 0) ) {
832 // allocate non-executable,read-only segments from end of read only shared region
833 seg.setNewAddress(currentReadOnlyAddress);
834 currentReadOnlyAddress += pageAlign(seg.size());
835 }
836 else if ( seg.writable() && seg.executable() && it->layout->hasSplitSegInfo() ) {
837 // allocate IMPORT segments to end of writable shared region
838 seg.setNewAddress(currentWritableExecutableAddress);
839 currentWritableExecutableAddress += pageAlign(seg.size());
840 }
841 }
842 }
843
844 // append all LINKEDIT segments at end of all read-only segments
845 fLinkEditsStartAddress = currentReadOnlyAddress;
846 fFirstLinkEditSegment = NULL;
847 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
848 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
849 for(int i=0; i < segs.size(); ++i) {
850 MachOLayoutAbstraction::Segment& seg = segs[i];
851 if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
852 if ( fFirstLinkEditSegment == NULL )
853 fFirstLinkEditSegment = &seg;
854 // allocate non-executable,read-only segments from end of read only shared region
855 seg.setNewAddress(currentReadOnlyAddress);
856 currentReadOnlyAddress += pageAlign(seg.size());
857 }
858 }
859 }
860 fLinkEditsTotalUnoptimizedSize = (currentReadOnlyAddress - fLinkEditsStartAddress + 4095) & (-4096);
861
862
863 // populate large mappings
864 uint64_t cacheFileOffset = 0;
865 if ( currentExecuteAddress > sharedRegionReadOnlyStartAddress() + 0x3000 ) {
866 shared_file_mapping_np executeMapping;
867 executeMapping.sfm_address = sharedRegionReadOnlyStartAddress();
868 executeMapping.sfm_size = currentExecuteAddress - sharedRegionReadOnlyStartAddress();
869 executeMapping.sfm_file_offset = cacheFileOffset;
870 executeMapping.sfm_max_prot = VM_PROT_READ | VM_PROT_EXECUTE;
871 executeMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_EXECUTE;
872 fMappings.push_back(executeMapping);
873 cacheFileOffset += executeMapping.sfm_size;
874
875 shared_file_mapping_np writableMapping;
876 writableMapping.sfm_address = sharedRegionWritableStartAddress();
877 writableMapping.sfm_size = currentWritableAddress - sharedRegionWritableStartAddress();
878 writableMapping.sfm_file_offset = cacheFileOffset;
879 writableMapping.sfm_max_prot = VM_PROT_READ | VM_PROT_WRITE;
880 writableMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_WRITE;
881 fMappings.push_back(writableMapping);
882 cacheFileOffset += writableMapping.sfm_size;
883
884 if ( currentWritableExecutableAddress > startWritableExecutableAddress ) {
885 shared_file_mapping_np writableExecutableMapping;
886 writableExecutableMapping.sfm_address = startWritableExecutableAddress;
887 writableExecutableMapping.sfm_size = currentWritableExecutableAddress - startWritableExecutableAddress;
888 writableExecutableMapping.sfm_file_offset= cacheFileOffset;
889 writableExecutableMapping.sfm_max_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
890 writableExecutableMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
891 fMappings.push_back(writableExecutableMapping);
892 cacheFileOffset += writableExecutableMapping.sfm_size;
893 }
894
895 // make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
896 shared_file_mapping_np readOnlyMapping;
897 readOnlyMapping.sfm_address = currentExecuteAddress;
898 readOnlyMapping.sfm_size = currentReadOnlyAddress - currentExecuteAddress;
899 readOnlyMapping.sfm_file_offset = cacheFileOffset;
900 readOnlyMapping.sfm_max_prot = VM_PROT_READ;
901 readOnlyMapping.sfm_init_prot = VM_PROT_READ;
902 fMappings.push_back(readOnlyMapping);
903 cacheFileOffset += readOnlyMapping.sfm_size;
904 }
905 else {
906 // empty cache
907 shared_file_mapping_np cacheHeaderMapping;
908 cacheHeaderMapping.sfm_address = sharedRegionWritableStartAddress();
909 cacheHeaderMapping.sfm_size = 0x3000;
910 cacheHeaderMapping.sfm_file_offset = cacheFileOffset;
911 cacheHeaderMapping.sfm_max_prot = VM_PROT_READ;
912 cacheHeaderMapping.sfm_init_prot = VM_PROT_READ;
913 fMappings.push_back(cacheHeaderMapping);
914 cacheFileOffset += cacheHeaderMapping.sfm_size;
915 }
916 }
917
918
919 template <typename A>
920 uint64_t SharedCache<A>::cacheFileOffsetForAddress(uint64_t addr)
921 {
922 for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
923 if ( (it->sfm_address <= addr) && (addr < it->sfm_address+it->sfm_size) )
924 return it->sfm_file_offset + addr - it->sfm_address;
925 }
926 throwf("address 0x%0llX is not in cache", addr);
927 }
928
929
930 template <typename A>
931 uint64_t SharedCache<A>::mappedCacheAddressForAddress(uint64_t addr)
932 {
933 if (!addr) return 0;
934 else return (uint64_t)(fInMemoryCache + cacheFileOffsetForAddress(addr));
935 }
936
937
938 template <typename A>
939 bool SharedCache<A>::notUpToDate(const void* cache)
940 {
941 dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
942 // not valid if header signature is wrong
943 const char* archPairName = fArchGraph->archName();
944 char temp[16];
945 strcpy(temp, "dyld_v1 ");
946 strcpy(&temp[15-strlen(archPairName)], archPairName);
947 if ( strcmp(header->magic(), temp) != 0 ) {
948 if ( fVerify ) {
949 fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archName());
950 return false;
951 }
952 else {
953 fprintf(stderr, "update_dyld_shared_cache[%u] current cache file has invalid header\n", getpid());
954 return true;
955 }
956 }
957 // not valid if count of images does not match current images needed
958 if ( header->imagesCount() != fDylibs.size() ) {
959 if ( fVerify ) {
960 fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archName());
961 return false;
962 }
963 else {
964 fprintf(stderr, "update_dyld_shared_cache[%u] current cache file is invalid because it contains a different set of dylibs\n", getpid());
965 return true;
966 }
967 }
968 // verify every dylib in constructed graph is in existing cache with same inode and modTime
969 std::map<const MachOLayoutAbstraction*, uint32_t> sortingMap;
970 const dyldCacheImageInfo<E>* imagesStart = (dyldCacheImageInfo<E>*)((uint8_t*)cache + header->imagesOffset());
971 const dyldCacheImageInfo<E>* imagesEnd = &imagesStart[header->imagesCount()];
972 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
973 bool found = false;
974 //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
975 for(const dyldCacheImageInfo<E>* cacheEntry = imagesStart; cacheEntry < imagesEnd; ++cacheEntry) {
976 if ( fVerify ) {
977 // in -verify mode, just match by path and warn if file looks different
978 if ( strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0 ) {
979 found = true;
980 sortingMap[it->layout] = cacheEntry-imagesStart;
981 if ( (cacheEntry->inode() != it->info.inode) || (cacheEntry->modTime() != it->info.modTime) ) {
982 fprintf(stderr, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n",
983 getpid(), archName(), it->layout->getID().name);
984 }
985 break;
986 }
987 }
988 else {
989 // in normal update mode, everything has to match for cache to be up-to-date
990 if ( (cacheEntry->inode() == it->info.inode)
991 && (cacheEntry->modTime() == it->info.modTime)
992 && (strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0) ) {
993 found = true;
994 break;
995 }
996 }
997 }
998 if ( !found ) {
999 if ( fVerify ) {
1000 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);
1001 }
1002 else {
1003 fprintf(stderr, "update_dyld_shared_cache[%u] current %s cache file invalid because %s has changed\n", getpid(), archName(), it->layout->getID().name);
1004 return true;
1005 }
1006 }
1007 }
1008 // all dylibs in existing cache file match those determined need to be in shared cache
1009 if ( fVerify ) {
1010 // sort fDylibs to match existing cache file so we can compare content
1011 std::sort(fDylibs.begin(), fDylibs.end(), Sorter(sortingMap));
1012 //fprintf(stderr, "dylibs sorted like existing cache:\n");
1013 //for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1014 // fprintf(stderr," %s\n", it->layout->getID().name);
1015 //}
1016 // do regenerate a new cache so we can compare content with existing
1017 return true;
1018 }
1019 else {
1020 // existing cache file is up-to-date, don't need to regenerate
1021 return false;
1022 }
1023 }
1024
1025
1026 template <typename A>
1027 bool SharedCache<A>::notUpToDate(const char* path)
1028 {
1029 // mmap existing cache file
1030 int fd = ::open(path, O_RDONLY);
1031 if ( fd == -1 )
1032 return true;
1033 struct stat stat_buf;
1034 ::fstat(fd, &stat_buf);
1035 uint8_t* mappingAddr = (uint8_t*)mmap(NULL, stat_buf.st_size, PROT_READ , MAP_FILE | MAP_PRIVATE, fd, 0);
1036 ::close(fd);
1037 if ( mappingAddr == (uint8_t*)(-1) )
1038 return true;
1039
1040 // validate it
1041 bool result = this->notUpToDate(mappingAddr);
1042 if ( fVerify ) {
1043 // don't unmap yet, leave so it can be verified later
1044 fExistingCacheForVerification = mappingAddr;
1045 }
1046 else {
1047 // unmap
1048 ::munmap(mappingAddr, stat_buf.st_size);
1049 if ( verbose && !result )
1050 fprintf(stderr, "update_dyld_shared_cache: %s is up-to-date\n", path);
1051 }
1052 return result;
1053 }
1054
1055 class CStringEquals
1056 {
1057 public:
1058 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
1059 };
1060
1061 class StringPool
1062 {
1063 public:
1064 StringPool();
1065 const char* getBuffer();
1066 uint32_t size();
1067 uint32_t add(const char* str);
1068 uint32_t addUnique(const char* str);
1069 const char* stringAtIndex(uint32_t) const;
1070 private:
1071 typedef __gnu_cxx::hash_map<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
1072
1073 char* fBuffer;
1074 uint32_t fBufferAllocated;
1075 uint32_t fBufferUsed;
1076 StringToOffset fUniqueStrings;
1077 };
1078
1079
1080 StringPool::StringPool()
1081 : fBufferUsed(0), fBufferAllocated(32*1024*1024)
1082 {
1083 fBuffer = (char*)malloc(fBufferAllocated);
1084 }
1085
1086 uint32_t StringPool::add(const char* str)
1087 {
1088 uint32_t len = strlen(str);
1089 if ( (fBufferUsed + len + 1) > fBufferAllocated ) {
1090 // grow buffer
1091 throw "string buffer exhausted";
1092 }
1093 strcpy(&fBuffer[fBufferUsed], str);
1094 uint32_t result = fBufferUsed;
1095 fUniqueStrings[&fBuffer[fBufferUsed]] = result;
1096 fBufferUsed += len+1;
1097 return result;
1098 }
1099
1100 uint32_t StringPool::addUnique(const char* str)
1101 {
1102 StringToOffset::iterator pos = fUniqueStrings.find(str);
1103 if ( pos != fUniqueStrings.end() )
1104 return pos->second;
1105 else {
1106 //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
1107 return this->add(str);
1108 }
1109 }
1110
1111 uint32_t StringPool::size()
1112 {
1113 return fBufferUsed;
1114 }
1115
1116 const char* StringPool::getBuffer()
1117 {
1118 return fBuffer;
1119 }
1120
1121 const char* StringPool::stringAtIndex(uint32_t index) const
1122 {
1123 return &fBuffer[index];
1124 }
1125
1126
1127 template <typename A>
1128 class LinkEditOptimizer
1129 {
1130 public:
1131 LinkEditOptimizer(const MachOLayoutAbstraction&, uint8_t*, StringPool&);
1132 virtual ~LinkEditOptimizer() {}
1133
1134 void copyBindInfo(uint32_t&);
1135 void copyWeakBindInfo(uint32_t&);
1136 void copyLazyBindInfo(uint32_t&);
1137 void copyExportInfo(uint32_t&);
1138 void copyLocalSymbols(uint32_t symbolTableOffset, uint32_t&);
1139 void copyExportedSymbols(uint32_t symbolTableOffset, uint32_t&);
1140 void copyImportedSymbols(uint32_t symbolTableOffset, uint32_t&);
1141 void copyExternalRelocations(uint32_t& offset);
1142 void copyIndirectSymbolTable(uint32_t& offset);
1143 void updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset,
1144 uint32_t linkEditsFileOffset, bool keepSignatures);
1145
1146
1147 protected:
1148 typedef typename A::P P;
1149 typedef typename A::P::E E;
1150 typedef typename A::P::uint_t pint_t;
1151
1152 private:
1153
1154 const macho_header<P>* fHeader;
1155 uint8_t* fNewLinkEditStart;
1156 uint8_t* fLinkEditBase;
1157 const MachOLayoutAbstraction& fLayout;
1158 macho_dyld_info_command<P>* fDyldInfo;
1159 macho_dysymtab_command<P>* fDynamicSymbolTable;
1160 macho_symtab_command<P>* fSymbolTableLoadCommand;
1161 const macho_nlist<P>* fSymbolTable;
1162 const char* fStrings;
1163 StringPool& fNewStringPool;
1164 std::map<uint32_t,uint32_t> fOldToNewSymbolIndexes;
1165 uint32_t fBindInfoOffsetIntoNewLinkEdit;
1166 uint32_t fBindInfoSizeInNewLinkEdit;
1167 uint32_t fWeakBindInfoOffsetIntoNewLinkEdit;
1168 uint32_t fWeakBindInfoSizeInNewLinkEdit;
1169 uint32_t fLazyBindInfoOffsetIntoNewLinkEdit;
1170 uint32_t fLazyBindInfoSizeInNewLinkEdit;
1171 uint32_t fExportInfoOffsetIntoNewLinkEdit;
1172 uint32_t fExportInfoSizeInNewLinkEdit;
1173 uint32_t fSymbolTableStartOffsetInNewLinkEdit;
1174 uint32_t fLocalSymbolsStartIndexInNewLinkEdit;
1175 uint32_t fLocalSymbolsCountInNewLinkEdit;
1176 uint32_t fExportedSymbolsStartIndexInNewLinkEdit;
1177 uint32_t fExportedSymbolsCountInNewLinkEdit;
1178 uint32_t fImportSymbolsStartIndexInNewLinkEdit;
1179 uint32_t fImportedSymbolsCountInNewLinkEdit;
1180 uint32_t fExternalRelocationsOffsetIntoNewLinkEdit;
1181 uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit;
1182 };
1183
1184
1185
1186 template <typename A>
1187 LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, uint8_t* newLinkEdit, StringPool& stringPool)
1188 : fLayout(layout), fLinkEditBase(NULL), fNewLinkEditStart(newLinkEdit), fDyldInfo(NULL),
1189 fDynamicSymbolTable(NULL), fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
1190 fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
1191 fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
1192 fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
1193 fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
1194 fSymbolTableStartOffsetInNewLinkEdit(0),
1195 fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
1196 fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
1197 fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
1198 fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0)
1199
1200 {
1201 fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
1202
1203 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
1204 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
1205 const MachOLayoutAbstraction::Segment& seg = *it;
1206 if ( strcmp(seg.name(), "__LINKEDIT") == 0 )
1207 fLinkEditBase = (uint8_t*)seg.mappedAddress() - seg.fileOffset();
1208 }
1209 if ( fLinkEditBase == NULL )
1210 throw "no __LINKEDIT segment";
1211
1212 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
1213 const uint32_t cmd_count = fHeader->ncmds();
1214 const macho_load_command<P>* cmd = cmds;
1215 for (uint32_t i = 0; i < cmd_count; ++i) {
1216 switch (cmd->cmd()) {
1217 case LC_SYMTAB:
1218 {
1219 fSymbolTableLoadCommand = (macho_symtab_command<P>*)cmd;
1220 fSymbolTable = (macho_nlist<P>*)(&fLinkEditBase[fSymbolTableLoadCommand->symoff()]);
1221 fStrings = (char*)&fLinkEditBase[fSymbolTableLoadCommand->stroff()];
1222 }
1223 break;
1224 case LC_DYSYMTAB:
1225 fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
1226 break;
1227 case LC_DYLD_INFO:
1228 case LC_DYLD_INFO_ONLY:
1229 fDyldInfo = (macho_dyld_info_command<P>*)cmd;
1230 break;
1231 }
1232 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
1233 }
1234 if ( fSymbolTable == NULL )
1235 throw "no LC_SYMTAB";
1236 if ( fDynamicSymbolTable == NULL )
1237 throw "no LC_DYSYMTAB";
1238
1239 }
1240
1241
1242 template <typename A>
1243 class SymbolSorter
1244 {
1245 public:
1246 typedef typename A::P P;
1247 SymbolSorter(const StringPool& pool) : fStringPool(pool) {}
1248 bool operator()(const macho_nlist<P>& left, const macho_nlist<P>& right) {
1249 return (strcmp(fStringPool.stringAtIndex(left.n_strx()) , fStringPool.stringAtIndex(right.n_strx())) < 0);
1250 }
1251
1252 private:
1253 const StringPool& fStringPool;
1254 };
1255
1256
1257 template <typename A>
1258 void LinkEditOptimizer<A>::copyBindInfo(uint32_t& offset)
1259 {
1260 if ( (fDyldInfo != NULL) && (fDyldInfo->bind_off() != 0) ) {
1261 fBindInfoOffsetIntoNewLinkEdit = offset;
1262 fBindInfoSizeInNewLinkEdit = fDyldInfo->bind_size();
1263 memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->bind_off()], fDyldInfo->bind_size());
1264 offset += fDyldInfo->bind_size();
1265 }
1266 }
1267
1268 template <typename A>
1269 void LinkEditOptimizer<A>::copyWeakBindInfo(uint32_t& offset)
1270 {
1271 if ( (fDyldInfo != NULL) && (fDyldInfo->weak_bind_off() != 0) ) {
1272 fWeakBindInfoOffsetIntoNewLinkEdit = offset;
1273 fWeakBindInfoSizeInNewLinkEdit = fDyldInfo->weak_bind_size();
1274 memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->weak_bind_off()], fDyldInfo->weak_bind_size());
1275 offset += fDyldInfo->weak_bind_size();
1276 }
1277 }
1278
1279 template <typename A>
1280 void LinkEditOptimizer<A>::copyLazyBindInfo(uint32_t& offset)
1281 {
1282 if ( (fDyldInfo != NULL) && (fDyldInfo->lazy_bind_off() != 0) ) {
1283 fLazyBindInfoOffsetIntoNewLinkEdit = offset;
1284 fLazyBindInfoSizeInNewLinkEdit = fDyldInfo->lazy_bind_size();
1285 memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->lazy_bind_off()], fDyldInfo->lazy_bind_size());
1286 offset += fDyldInfo->lazy_bind_size();
1287 }
1288 }
1289
1290 template <typename A>
1291 void LinkEditOptimizer<A>::copyExportInfo(uint32_t& offset)
1292 {
1293 if ( (fDyldInfo != NULL) && (fDyldInfo->export_off() != 0) ) {
1294 fExportInfoOffsetIntoNewLinkEdit = offset;
1295 fExportInfoSizeInNewLinkEdit = fDyldInfo->export_size();
1296 // warning, export_off is only 32-bits so if the trie grows it must be allocated with 32-bits of fLinkeditBase
1297 memcpy(fNewLinkEditStart+offset, fLinkEditBase+(int32_t)fDyldInfo->export_off(), fDyldInfo->export_size());
1298 offset += fDyldInfo->export_size();
1299 }
1300 }
1301
1302
1303
1304 template <typename A>
1305 void LinkEditOptimizer<A>::copyLocalSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
1306 {
1307 fLocalSymbolsStartIndexInNewLinkEdit = symbolIndex;
1308 fSymbolTableStartOffsetInNewLinkEdit = symbolTableOffset + symbolIndex*sizeof(macho_nlist<P>);
1309 macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
1310 const macho_nlist<P>* const firstLocal = &fSymbolTable[fDynamicSymbolTable->ilocalsym()];
1311 const macho_nlist<P>* const lastLocal = &fSymbolTable[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
1312 uint32_t oldIndex = fDynamicSymbolTable->ilocalsym();
1313 for (const macho_nlist<P>* entry = firstLocal; entry < lastLocal; ++entry, ++oldIndex) {
1314 if ( (entry->n_type() & N_TYPE) == N_SECT ) {
1315 macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
1316 *newSymbolEntry = *entry;
1317 newSymbolEntry->set_n_strx(fNewStringPool.add(&fStrings[entry->n_strx()]));
1318 ++symbolIndex;
1319 }
1320 }
1321 fLocalSymbolsCountInNewLinkEdit = symbolIndex - fLocalSymbolsStartIndexInNewLinkEdit;
1322 //fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1323 }
1324
1325
1326 template <typename A>
1327 void LinkEditOptimizer<A>::copyExportedSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
1328 {
1329 fExportedSymbolsStartIndexInNewLinkEdit = symbolIndex;
1330 macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
1331 const macho_nlist<P>* const firstExport = &fSymbolTable[fDynamicSymbolTable->iextdefsym()];
1332 const macho_nlist<P>* const lastExport = &fSymbolTable[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
1333 uint32_t oldIndex = fDynamicSymbolTable->iextdefsym();
1334 for (const macho_nlist<P>* entry = firstExport; entry < lastExport; ++entry, ++oldIndex) {
1335 if ( ((entry->n_type() & N_TYPE) == N_SECT) && (strncmp(&fStrings[entry->n_strx()], ".objc_", 6) != 0)
1336 && (strncmp(&fStrings[entry->n_strx()], "$ld$", 4) != 0) ) {
1337 macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
1338 *newSymbolEntry = *entry;
1339 newSymbolEntry->set_n_strx(fNewStringPool.add(&fStrings[entry->n_strx()]));
1340 fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
1341 ++symbolIndex;
1342 }
1343 }
1344 fExportedSymbolsCountInNewLinkEdit = symbolIndex - fExportedSymbolsStartIndexInNewLinkEdit;
1345 //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1346 // sort by name, so that dyld does not need a toc
1347 macho_nlist<P>* newSymbolsStart = &newSymbolTableStart[fExportedSymbolsStartIndexInNewLinkEdit];
1348 macho_nlist<P>* newSymbolsEnd = &newSymbolTableStart[fExportedSymbolsStartIndexInNewLinkEdit+fExportedSymbolsCountInNewLinkEdit];
1349 std::sort(newSymbolsStart, newSymbolsEnd, SymbolSorter<A>(fNewStringPool));
1350 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1351 // fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1352 }
1353
1354
1355 template <typename A>
1356 void LinkEditOptimizer<A>::copyImportedSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
1357 {
1358 fImportSymbolsStartIndexInNewLinkEdit = symbolIndex;
1359 macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
1360 const macho_nlist<P>* const firstImport = &fSymbolTable[fDynamicSymbolTable->iundefsym()];
1361 const macho_nlist<P>* const lastImport = &fSymbolTable[fDynamicSymbolTable->iundefsym()+fDynamicSymbolTable->nundefsym()];
1362 uint32_t oldIndex = fDynamicSymbolTable->iundefsym();
1363 for (const macho_nlist<P>* entry = firstImport; entry < lastImport; ++entry, ++oldIndex) {
1364 if ( ((entry->n_type() & N_TYPE) == N_UNDF) && (strncmp(&fStrings[entry->n_strx()], ".objc_", 6) != 0) ) {
1365 macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
1366 *newSymbolEntry = *entry;
1367 newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
1368 fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
1369 ++symbolIndex;
1370 }
1371 }
1372 fImportedSymbolsCountInNewLinkEdit = symbolIndex - fImportSymbolsStartIndexInNewLinkEdit;
1373 //fprintf(stderr, "%u imports starting at %u for %s\n", fImportedSymbolsCountInNewLinkEdit, fImportSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
1374 //macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit];
1375 //macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fImportSymbolsStartIndexInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit];
1376 //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
1377 // fprintf(stderr, "\t%u\t%s\n", (entry-newSymbolsStart)+fImportSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
1378 }
1379
1380
1381 template <typename A>
1382 void LinkEditOptimizer<A>::copyExternalRelocations(uint32_t& offset)
1383 {
1384 fExternalRelocationsOffsetIntoNewLinkEdit = offset;
1385 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->extreloff()]);
1386 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nextrel()];
1387 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1388 macho_relocation_info<P>* newReloc = (macho_relocation_info<P>*)(&fNewLinkEditStart[offset]);
1389 *newReloc = *reloc;
1390 uint32_t newSymbolIndex = fOldToNewSymbolIndexes[reloc->r_symbolnum()];
1391 //fprintf(stderr, "copyExternalRelocations() old=%d, new=%u name=%s in %s\n", reloc->r_symbolnum(), newSymbolIndex,
1392 // &fStrings[fSymbolTable[reloc->r_symbolnum()].n_strx()], fLayout.getFilePath());
1393 newReloc->set_r_symbolnum(newSymbolIndex);
1394 offset += sizeof(macho_relocation_info<P>);
1395 }
1396 }
1397
1398 template <typename A>
1399 void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
1400 {
1401 fIndirectSymbolTableOffsetInfoNewLinkEdit = offset;
1402 const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicSymbolTable->indirectsymoff()];
1403 uint32_t* newIndirectTable = (uint32_t*)&fNewLinkEditStart[offset];
1404 for (int i=0; i < fDynamicSymbolTable->nindirectsyms(); ++i) {
1405 uint32_t oldSymbolIndex = E::get32(indirectTable[i]);
1406 uint32_t newSymbolIndex = oldSymbolIndex;
1407 if ( (oldSymbolIndex != INDIRECT_SYMBOL_ABS) && (oldSymbolIndex != INDIRECT_SYMBOL_LOCAL) ) {
1408 newSymbolIndex = fOldToNewSymbolIndexes[oldSymbolIndex];
1409 //fprintf(stderr, "copyIndirectSymbolTable() old=%d, new=%u name=%s in %s\n", oldSymbolIndex, newSymbolIndex,
1410 // &fStrings[fSymbolTable[oldSymbolIndex].n_strx()], fLayout.getFilePath());
1411 }
1412 E::set32(newIndirectTable[i], newSymbolIndex);
1413 }
1414 offset += (fDynamicSymbolTable->nindirectsyms() * 4);
1415 }
1416
1417 template <typename A>
1418 void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset,
1419 uint32_t linkEditsFileOffset, bool keepSignatures)
1420 {
1421 // set LINKEDIT segment commmand to new merged LINKEDIT
1422 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
1423 const uint32_t cmd_count = fHeader->ncmds();
1424 const macho_load_command<P>* cmd = cmds;
1425 for (uint32_t i = 0; i < cmd_count; ++i) {
1426 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1427 macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
1428 if ( strcmp(seg->segname(), "__LINKEDIT") == 0 ) {
1429 seg->set_vmaddr(newVMAddress);
1430 seg->set_vmsize(size);
1431 seg->set_filesize(size);
1432 seg->set_fileoff(linkEditsFileOffset);
1433 }
1434 }
1435 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
1436 }
1437
1438 // update dyld_info with new offsets
1439 if ( fDyldInfo != NULL ) {
1440 fDyldInfo->set_rebase_off(0);
1441 fDyldInfo->set_rebase_size(0);
1442 fDyldInfo->set_bind_off(linkEditsFileOffset+fBindInfoOffsetIntoNewLinkEdit);
1443 fDyldInfo->set_bind_size(fBindInfoSizeInNewLinkEdit);
1444 fDyldInfo->set_weak_bind_off(linkEditsFileOffset+fWeakBindInfoOffsetIntoNewLinkEdit);
1445 fDyldInfo->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit);
1446 fDyldInfo->set_lazy_bind_off(linkEditsFileOffset+fLazyBindInfoOffsetIntoNewLinkEdit);
1447 fDyldInfo->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit);
1448 fDyldInfo->set_export_off(linkEditsFileOffset+fExportInfoOffsetIntoNewLinkEdit);
1449 fDyldInfo->set_export_size(fExportInfoSizeInNewLinkEdit);
1450
1451 // fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
1452 // fprintf(stderr, " bind_off=0x%08X\n", fDyldInfo->bind_off());
1453 // fprintf(stderr, " export_off=0x%08X\n", fDyldInfo->export_off());
1454 // fprintf(stderr, " export_size=%d\n", fDyldInfo->export_size());
1455
1456 }
1457
1458 // update symbol table and dynamic symbol table with new offsets
1459 fSymbolTableLoadCommand->set_symoff(linkEditsFileOffset+fSymbolTableStartOffsetInNewLinkEdit);
1460 fSymbolTableLoadCommand->set_nsyms(fLocalSymbolsCountInNewLinkEdit+fExportedSymbolsCountInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit);
1461 fSymbolTableLoadCommand->set_stroff(linkEditsFileOffset+stringPoolOffset);
1462 fSymbolTableLoadCommand->set_strsize(fNewStringPool.size());
1463 fDynamicSymbolTable->set_ilocalsym(0);
1464 fDynamicSymbolTable->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit);
1465 fDynamicSymbolTable->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit-fLocalSymbolsStartIndexInNewLinkEdit);
1466 fDynamicSymbolTable->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit);
1467 fDynamicSymbolTable->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit-fLocalSymbolsStartIndexInNewLinkEdit);
1468 fDynamicSymbolTable->set_nundefsym(fImportedSymbolsCountInNewLinkEdit);
1469 fDynamicSymbolTable->set_tocoff(0);
1470 fDynamicSymbolTable->set_ntoc(0);
1471 fDynamicSymbolTable->set_modtaboff(0);
1472 fDynamicSymbolTable->set_nmodtab(0);
1473 fDynamicSymbolTable->set_indirectsymoff(linkEditsFileOffset+fIndirectSymbolTableOffsetInfoNewLinkEdit);
1474 fDynamicSymbolTable->set_extreloff(linkEditsFileOffset+fExternalRelocationsOffsetIntoNewLinkEdit);
1475 fDynamicSymbolTable->set_locreloff(0);
1476 fDynamicSymbolTable->set_nlocrel(0);
1477
1478 // now remove load commands no longer needed
1479 const macho_load_command<P>* srcCmd = cmds;
1480 macho_load_command<P>* dstCmd = (macho_load_command<P>*)cmds;
1481 int32_t newCount = 0;
1482 for (uint32_t i = 0; i < cmd_count; ++i) {
1483 uint32_t cmdSize = srcCmd->cmdsize();
1484 switch ( srcCmd->cmd() ) {
1485 case LC_SEGMENT_SPLIT_INFO:
1486 // don't copy
1487 break;
1488 case LC_CODE_SIGNATURE:
1489 if ( !keepSignatures )
1490 break;
1491 // otherwise fall into copy case
1492 default:
1493 memmove(dstCmd, srcCmd, cmdSize);
1494 dstCmd = (macho_load_command<P>*)(((uint8_t*)dstCmd)+cmdSize);
1495 ++newCount;
1496 break;
1497 }
1498 srcCmd = (const macho_load_command<P>*)(((uint8_t*)srcCmd)+cmdSize);
1499 }
1500 // zero out stuff removed
1501 bzero(dstCmd, (uint8_t*)srcCmd - (uint8_t*)dstCmd);
1502
1503 // update mach_header
1504 macho_header<P>* writableHeader = (macho_header<P>*)fHeader;
1505 writableHeader->set_ncmds(newCount);
1506 writableHeader->set_sizeofcmds((uint8_t*)dstCmd - ((uint8_t*)fHeader + sizeof(macho_header<P>)));
1507
1508 // this invalidates some ivars
1509 fDynamicSymbolTable = NULL;
1510 fSymbolTableLoadCommand = NULL;
1511 fDyldInfo = NULL;
1512 fSymbolTable = NULL;
1513 fStrings = NULL;
1514 }
1515
1516
1517
1518 template <typename A>
1519 uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
1520 {
1521 // allocate space for optimized LINKEDIT area
1522 uint8_t* newLinkEdit = new uint8_t[fLinkEditsTotalUnoptimizedSize];
1523 bzero(newLinkEdit, fLinkEditsTotalUnoptimizedSize);
1524
1525 // make a string pool
1526 StringPool stringPool;
1527
1528 // create optimizer object for each LINKEDIT segment
1529 std::vector<LinkEditOptimizer<A>*> optimizers;
1530 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1531 optimizers.push_back(new LinkEditOptimizer<A>(*it->layout, newLinkEdit, stringPool));
1532 }
1533
1534 // rebase info is not copied because images in shared cache are never rebased
1535
1536 // copy weak bind info
1537 uint32_t offset = 0;
1538 fOffsetOfWeakBindInfoInCombinedLinkedit = offset;
1539 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1540 (*it)->copyWeakBindInfo(offset);
1541 }
1542
1543 // copy export info
1544 fOffsetOfExportInfoInCombinedLinkedit = offset;
1545 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1546 (*it)->copyExportInfo(offset);
1547 }
1548
1549 // copy bind info
1550 fOffsetOfBindInfoInCombinedLinkedit = offset;
1551 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1552 (*it)->copyBindInfo(offset);
1553 }
1554
1555 // copy lazy bind info
1556 fOffsetOfLazyBindInfoInCombinedLinkedit = offset;
1557 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1558 (*it)->copyLazyBindInfo(offset);
1559 }
1560
1561 // copy symbol table entries
1562 fOffsetOfOldSymbolTableInfoInCombinedLinkedit = offset;
1563 uint32_t symbolTableOffset = offset;
1564 uint32_t symbolTableIndex = 0;
1565 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1566 (*it)->copyLocalSymbols(symbolTableOffset, symbolTableIndex);
1567 (*it)->copyExportedSymbols(symbolTableOffset, symbolTableIndex);
1568 (*it)->copyImportedSymbols(symbolTableOffset, symbolTableIndex);
1569 }
1570
1571 // copy external relocations, 8-byte aligned after end of symbol table
1572 uint32_t externalRelocsOffset = symbolTableOffset + (symbolTableIndex * sizeof(macho_nlist<typename A::P>) + 7) & (-8);
1573 //uint32_t externalRelocsStartOffset = externalRelocsOffset;
1574 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1575 (*it)->copyExternalRelocations(externalRelocsOffset);
1576 }
1577
1578 // copy indirect symbol tables
1579 uint32_t indirectSymbolTableOffset = externalRelocsOffset;
1580 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1581 (*it)->copyIndirectSymbolTable(indirectSymbolTableOffset);
1582 }
1583
1584 // copy string pool
1585 uint32_t stringPoolOffset = indirectSymbolTableOffset;
1586 memcpy(&newLinkEdit[stringPoolOffset], stringPool.getBuffer(), stringPool.size());
1587
1588 // find new size
1589 fLinkEditsTotalOptimizedSize = (stringPoolOffset + stringPool.size() + 4095) & (-4096);
1590
1591 // choose new linkedit file offset
1592 uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionReadOnlyStartAddress();
1593
1594 // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
1595 for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
1596 (*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalUnoptimizedSize, stringPoolOffset, linkEditsFileOffset, keepSignatures);
1597 }
1598
1599 //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
1600 //printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
1601
1602 // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
1603 memcpy(fFirstLinkEditSegment->mappedAddress(), newLinkEdit, fLinkEditsTotalUnoptimizedSize);
1604
1605 // update all LINKEDIT Segment objects to point to same merged LINKEDIT area
1606 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1607 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
1608 for(int i=0; i < segs.size(); ++i) {
1609 MachOLayoutAbstraction::Segment& seg = segs[i];
1610 if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
1611 seg.setNewAddress(fLinkEditsStartAddress);
1612 seg.setMappedAddress(fFirstLinkEditSegment->mappedAddress());
1613 seg.setSize(fLinkEditsTotalOptimizedSize);
1614 seg.setFileSize(fLinkEditsTotalOptimizedSize);
1615 seg.setFileOffset(linkEditsFileOffset);
1616 }
1617 }
1618 }
1619
1620 // return new end of cache
1621 return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + fLinkEditsTotalOptimizedSize;
1622 }
1623
1624
1625
1626 template <typename A>
1627 class ObjCSelectorUniquer
1628 {
1629 private:
1630 objc_selopt::string_map fSelectorStrings;
1631 SharedCache<A> *fCache;
1632 size_t fCount;
1633
1634 public:
1635
1636 ObjCSelectorUniquer(SharedCache<A> *newCache)
1637 : fSelectorStrings()
1638 , fCache(newCache)
1639 , fCount(0)
1640 { }
1641
1642 typename A::P::uint_t visit(typename A::P::uint_t oldValue)
1643 {
1644 fCount++;
1645 const char *s = (const char *)
1646 fCache->mappedCacheAddressForAddress(oldValue);
1647 objc_selopt::string_map::iterator element =
1648 fSelectorStrings.insert(objc_selopt::string_map::value_type(s, oldValue)).first;
1649 return (typename A::P::uint_t)element->second;
1650 }
1651
1652 objc_selopt::string_map& strings() {
1653 return fSelectorStrings;
1654 }
1655
1656 size_t count() const { return fCount; }
1657 };
1658
1659 template <>
1660 void SharedCache<arm>::optimizeObjC()
1661 {
1662 // objc optimizations on arm not yet supported
1663 }
1664
1665 template <typename A>
1666 void SharedCache<A>::optimizeObjC()
1667 {
1668 if ( verbose ) {
1669 fprintf(stderr, "update_dyld_shared_cache: for %s, uniquing objc selectors\n", archName());
1670 }
1671
1672 // Find libobjc's __TEXT,__objc_selopt section
1673 const macho_section<P> *seloptSection = NULL;
1674 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1675 if (0 == strstr(it->layout->getFilePath(), "libobjc")) continue;
1676 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
1677 if ((seloptSection = mh->getSection("__TEXT", "__objc_selopt"))) break;
1678 }
1679
1680 if (!seloptSection) {
1681 warn(archName(), "couldn't find libobjc's unique selector section (selectors not optimized)");
1682 return;
1683 }
1684
1685 objc_selopt::objc_selopt_t *seloptData = (objc_selopt::objc_selopt_t *)
1686 mappedCacheAddressForAddress(seloptSection->addr());
1687 if (seloptSection->size() < sizeof(seloptData->version)) {
1688 warn(archName(), "libobjc's unique selector section is too small (selectors not optimized)");
1689 return;
1690 }
1691
1692 if (E::get32(seloptData->version) != objc_selopt::VERSION) {
1693 warn(archName(), "libobjc's unique selector section version is unrecognized (selectors not optimized)");
1694 return;
1695 }
1696
1697
1698 // Update selector references and build selector list
1699 ObjCSelectorUniquer<A> uniq(this);
1700
1701 // Heuristic: choose selectors from libraries with more cstring data first.
1702 // This tries to localize selector cstring memory.
1703 std::vector<LayoutInfo> sortedDylibs = fDylibs;
1704 std::sort(sortedDylibs.begin(), sortedDylibs.end(), ByCStringSectionSizeSorter());
1705
1706 for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
1707 const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
1708 LegacySelectorUpdater<A, ObjCSelectorUniquer<A> >::update(this, mh, uniq);
1709 SelectorUpdater<A, ObjCSelectorUniquer<A> >::update(this, mh, uniq);
1710 }
1711
1712 if ( verbose ) {
1713 fprintf(stderr, "update_dyld_shared_cache: for %s, found %zu unique objc selectors\n", archName(), uniq.strings().size());
1714 }
1715
1716 // Write selector hash table to libobjc's __TEXT,__objc_selopt section
1717 size_t bytesUsed;
1718 const char *err =
1719 objc_selopt::write_selopt(seloptData, seloptSection->addr(),
1720 seloptSection->size(), uniq.strings(),
1721 E::little_endian, &bytesUsed);
1722 if (err) {
1723 warn(archName(), err);
1724 return;
1725 }
1726
1727 if ( verbose ) {
1728 fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
1729 "(%d%%) used in libobjc unique selector section\n",
1730 archName(), bytesUsed, seloptSection->size(),
1731 (int)(bytesUsed / (double)seloptSection->size() * 100));
1732 fprintf(stderr, "update_dyld_shared_cache: for %s, "
1733 "updated %zu selector references\n",
1734 archName(), uniq.count());
1735 }
1736
1737 return;
1738 }
1739
1740
1741 static const char* sCleanupFile = NULL;
1742 static void cleanup(int sig)
1743 {
1744 ::signal(sig, SIG_DFL);
1745 if ( sCleanupFile != NULL )
1746 ::unlink(sCleanupFile);
1747 //if ( verbose )
1748 // fprintf(stderr, "update_dyld_shared_cache: deleting temp file in response to a signal\n");
1749 if ( sig == SIGINT )
1750 ::exit(1);
1751 }
1752
1753
1754 template <typename A>
1755 bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex,
1756 int archCount, bool keepSignatures)
1757 {
1758 bool didUpdate = false;
1759
1760 // already up to date?
1761 if ( force || fExistingIsNotUpToDate ) {
1762 if ( verbose )
1763 fprintf(stderr, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath);
1764 if ( fDylibs.size() == 0 ) {
1765 fprintf(stderr, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
1766 return false;
1767 }
1768 // delete existing cache while building the new one
1769 // this is a flag to dyld to stop pinging update_dyld_shared_cache
1770 if ( deleteExistingFirst )
1771 ::unlink(fCacheFilePath);
1772 uint8_t* inMemoryCache = NULL;
1773 uint32_t allocatedCacheSize = 0;
1774 char tempCachePath[strlen(fCacheFilePath)+16];
1775 sprintf(tempCachePath, "%s.tmp%u", fCacheFilePath, getpid());
1776 try {
1777 // allocate a memory block to hold cache
1778 uint32_t cacheFileSize = 0;
1779 for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
1780 uint32_t end = it->sfm_file_offset + it->sfm_size;
1781 if ( end > cacheFileSize )
1782 cacheFileSize = end;
1783 }
1784 if ( vm_allocate(mach_task_self(), (vm_address_t*)(&inMemoryCache), cacheFileSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
1785 throwf("can't vm_allocate cache of size %u", cacheFileSize);
1786 allocatedCacheSize = cacheFileSize;
1787 fInMemoryCache = inMemoryCache;
1788
1789 // fill in header
1790 dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)inMemoryCache;
1791 const char* archPairName = fArchGraph->archName();
1792 char temp[16];
1793 strcpy(temp, "dyld_v1 ");
1794 strcpy(&temp[15-strlen(archPairName)], archPairName);
1795 header->set_magic(temp);
1796 //header->set_architecture(arch());
1797 header->set_mappingOffset(sizeof(dyldCacheHeader<E>));
1798 header->set_mappingCount(fMappings.size());
1799 header->set_imagesOffset(header->mappingOffset() + fMappings.size()*sizeof(dyldCacheFileMapping<E>));
1800 header->set_imagesCount(fDylibs.size());
1801 header->set_dyldBaseAddress(fDyldBaseAddress);
1802 //header->set_dependenciesOffset(sizeof(dyldCacheHeader<E>) + fMappings.size()*sizeof(dyldCacheFileMapping<E>) + fDylibs.size()*sizeof(dyldCacheImageInfo<E>));
1803 //header->set_dependenciesCount(fDependencyPool.size());
1804
1805 // fill in mappings
1806 dyldCacheFileMapping<E>* mapping = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
1807 for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
1808 if ( verbose )
1809 fprintf(stderr, "update_dyld_shared_cache: cache mappings: address=0x%0llX, size=0x%0llX, fileOffset=0x%0llX, prot=0x%X\n",
1810 it->sfm_address, it->sfm_size, it->sfm_file_offset, it->sfm_init_prot);
1811 mapping->set_address(it->sfm_address);
1812 mapping->set_size(it->sfm_size);
1813 mapping->set_file_offset(it->sfm_file_offset);
1814 mapping->set_max_prot(it->sfm_max_prot);
1815 mapping->set_init_prot(it->sfm_init_prot);
1816 ++mapping;
1817 }
1818
1819 // fill in image table
1820 dyldCacheImageInfo<E>* image = (dyldCacheImageInfo<E>*)mapping;
1821 for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1822 image->set_address(it->info.address);
1823 image->set_modTime(it->info.modTime);
1824 image->set_inode(it->info.inode);
1825 image->set_pathFileOffset(cacheFileOffsetForAddress(it->info.address+it->info.pathFileOffset));
1826 //image->set_dependenciesStartOffset(it->info.dependenciesStartOffset);
1827 ++image;
1828 }
1829
1830 // copy each segment to cache buffer
1831 const int dylibCount = fDylibs.size();
1832 int dylibIndex = 0;
1833 int progressIndex = 0;
1834 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++dylibIndex) {
1835 const char* path = it->layout->getFilePath();
1836 int src = ::open(path, O_RDONLY, 0);
1837 if ( src == -1 )
1838 throwf("can't open file %s, errnor=%d", it->layout->getID().name, errno);
1839 // mark source as "don't cache"
1840 (void)fcntl(src, F_NOCACHE, 1);
1841 // verify file has not changed since dependency analysis
1842 struct stat stat_buf;
1843 if ( fstat(src, &stat_buf) == -1)
1844 throwf("can't stat open file %s, errno=%d", path, errno);
1845 if ( (it->layout->getInode() != stat_buf.st_ino) || (it->layout->getLastModTime() != stat_buf.st_mtime) )
1846 throwf("file modified during cache creation: %s", path);
1847
1848 if ( verbose )
1849 fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getID().name);
1850 try {
1851 const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
1852 for (int i=0; i < segs.size(); ++i) {
1853 const MachOLayoutAbstraction::Segment& seg = segs[i];
1854 if ( verbose )
1855 fprintf(stderr, "\t\tsegment %s, size=0x%0llX, cache address=0x%0llX\n", seg.name(), seg.fileSize(), seg.newAddress());
1856 if ( seg.size() > 0 ) {
1857 const uint64_t segmentSrcStartOffset = it->layout->getOffsetInUniversalFile()+seg.fileOffset();
1858 const uint64_t segmentSize = seg.fileSize();
1859 const uint64_t segmentDstStartOffset = cacheFileOffsetForAddress(seg.newAddress());
1860 ssize_t readResult = ::pread(src, &inMemoryCache[segmentDstStartOffset], segmentSize, segmentSrcStartOffset);
1861 if ( readResult != segmentSize ) {
1862 if ( readResult == -1 )
1863 throwf("read failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
1864 else
1865 throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s",
1866 segmentSize, segmentSrcStartOffset, readResult, it->layout->getID().name);
1867 }
1868 }
1869 }
1870 }
1871 catch (const char* msg) {
1872 throwf("%s while copying %s to shared cache", msg, it->layout->getID().name);
1873 }
1874 ::close(src);
1875 if ( progress ) {
1876 // assuming read takes 40% of time
1877 int nextProgressIndex = archIndex*100+(40*dylibIndex)/dylibCount;
1878 if ( nextProgressIndex != progressIndex )
1879 fprintf(stdout, "%3u/%u\n", nextProgressIndex, archCount*100);
1880 progressIndex = nextProgressIndex;
1881 }
1882 }
1883
1884 // set mapped address for each segment
1885 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1886 std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
1887 for (int i=0; i < segs.size(); ++i) {
1888 MachOLayoutAbstraction::Segment& seg = segs[i];
1889 if ( seg.size() > 0 )
1890 seg.setMappedAddress(inMemoryCache + cacheFileOffsetForAddress(seg.newAddress()));
1891 //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
1892 }
1893 }
1894
1895 // rebase each dylib in shared cache
1896 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1897 try {
1898 Rebaser<A> r(*it->layout);
1899 r.rebase();
1900 //if ( verbose )
1901 // fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
1902 }
1903 catch (const char* msg) {
1904 throwf("%s in %s", msg, it->layout->getID().name);
1905 }
1906 }
1907
1908 // merge/optimize all LINKEDIT segments
1909 if ( optimize ) {
1910 //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
1911 cacheFileSize = (this->optimizeLINKEDIT(keepSignatures) - inMemoryCache);
1912 //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
1913 // update header to reduce mapping size
1914 dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
1915 dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
1916 dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
1917 lastMapping->set_size(cacheFileSize-lastMapping->file_offset());
1918 // update fMappings so .map file will print correctly
1919 fMappings.back().sfm_size = cacheFileSize-fMappings.back().sfm_file_offset;
1920 }
1921
1922 if ( verbose )
1923 fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs.size());
1924 // instantiate a Binder for each image and add to map
1925 typename Binder<A>::Map map;
1926 std::vector<Binder<A>*> binders;
1927 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
1928 //fprintf(stderr, "binding %s\n", it->layout->getID().name);
1929 Binder<A>* binder = new Binder<A>(*it->layout, fDyldBaseAddress);
1930 binders.push_back(binder);
1931 // only add dylibs to map
1932 if ( it->layout->getID().name != NULL )
1933 map[it->layout->getID().name] = binder;
1934 }
1935
1936 // tell each Binder about the others
1937 for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
1938 (*it)->setDependentBinders(map);
1939 }
1940 // perform binding
1941 for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
1942 if ( verbose )
1943 fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it)->getDylibID());
1944 try {
1945 (*it)->bind();
1946 }
1947 catch (const char* msg) {
1948 throwf("%s in %s", msg, (*it)->getDylibID());
1949 }
1950 }
1951 // delete binders
1952 for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
1953 delete *it;
1954 }
1955
1956 // unique objc selectors and update other objc metadata
1957 if (optimize) {
1958 optimizeObjC();
1959 }
1960 if ( progress ) {
1961 // assuming objc optimizations takes 15% of time
1962 fprintf(stdout, "%3u/%u\n", (archIndex+1)*55, archCount*100);
1963 }
1964
1965 if ( fVerify ) {
1966 // new cache is built, compare header entries
1967 const dyldCacheHeader<E>* newHeader = (dyldCacheHeader<E>*)inMemoryCache;
1968 const dyldCacheHeader<E>* oldHeader = (dyldCacheHeader<E>*)fExistingCacheForVerification;
1969 if ( newHeader->mappingCount() != oldHeader->mappingCount() ) {
1970 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
1971 getpid(), archName());
1972 }
1973 const dyldCacheFileMapping<E>* newMappings = (dyldCacheFileMapping<E>*)&inMemoryCache[newHeader->mappingOffset()];
1974 const dyldCacheFileMapping<E>* oldMappings = (dyldCacheFileMapping<E>*)&fExistingCacheForVerification[oldHeader->mappingOffset()];
1975 for (int i=0; i < newHeader->mappingCount(); ++i) {
1976 if ( newMappings[i].address() != oldMappings[i].address() ) {
1977 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",
1978 getpid(), archName(), i, newMappings[i].address(), oldMappings[i].address() );
1979 }
1980 if ( newMappings[i].size() != oldMappings[i].size() ) {
1981 throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
1982 getpid(), archName(), i);
1983 }
1984 }
1985
1986 //fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
1987 //fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
1988 // compare content to existing cache page by page
1989 for (int offset=0; offset < cacheFileSize; offset += 4096) {
1990 if ( memcmp(&inMemoryCache[offset], &fExistingCacheForVerification[offset], 4096) != 0 ) {
1991 fprintf(stderr, "verifier found differences on page offset 0x%08X for %s:\n", offset, archName());
1992 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++dylibIndex) {
1993 const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
1994 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator sit = segs.begin(); sit != segs.end(); ++sit) {
1995 const MachOLayoutAbstraction::Segment& seg = *sit;
1996 if ( (seg.mappedAddress() <= &inMemoryCache[offset]) && (&inMemoryCache[offset] < ((uint8_t*)seg.mappedAddress() + seg.fileSize())) ) {
1997 // all LINKEDITs point to the same region, so just print one
1998 if ( strcmp(seg.name(), "__LINKEDIT") == 0 )
1999 fprintf(stderr, " in merged LINKEDIT segment\n");
2000 else
2001 fprintf(stderr, " in segment %s of dylib %s\n", seg.name(), it->layout->getID().name);
2002 break;
2003 }
2004 }
2005 }
2006 for (int po=0; po < 4096; po += 16) {
2007 if ( memcmp(&inMemoryCache[offset+po], &fExistingCacheForVerification[offset+po], 16) != 0 ) {
2008 fprintf(stderr, " existing: 0x%08X: ", offset+po);
2009 for ( int j=0; j < 16; ++j)
2010 fprintf(stderr, " 0x%02X", fExistingCacheForVerification[offset+po+j]);
2011 fprintf(stderr, "\n");
2012 fprintf(stderr, " should be: 0x%08X: ", offset+po);
2013 for ( int j=0; j < 16; ++j)
2014 fprintf(stderr, " 0x%02X", inMemoryCache[offset+po+j]);
2015 fprintf(stderr, "\n");
2016 }
2017 }
2018 }
2019 }
2020 }
2021 else {
2022 // install signal handlers to delete temp file if program is killed
2023 sCleanupFile = tempCachePath;
2024 ::signal(SIGINT, cleanup);
2025 ::signal(SIGBUS, cleanup);
2026 ::signal(SIGSEGV, cleanup);
2027
2028 // create var/db/dyld dirs if needed
2029 char dyldDirs[1024];
2030 strcpy(dyldDirs, fCacheFilePath);
2031 char* lastSlash = strrchr(dyldDirs, '/');
2032 if ( lastSlash != NULL )
2033 lastSlash[1] = '\0';
2034 struct stat stat_buf;
2035 if ( stat(dyldDirs, &stat_buf) != 0 ) {
2036 const char* afterSlash = &dyldDirs[1];
2037 char* slash;
2038 while ( (slash = strchr(afterSlash, '/')) != NULL ) {
2039 *slash = '\0';
2040 ::mkdir(dyldDirs, S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
2041 *slash = '/';
2042 afterSlash = slash+1;
2043 }
2044 }
2045
2046 // create temp file for cache
2047 int fd = ::open(tempCachePath, O_CREAT | O_RDWR | O_TRUNC, 0644);
2048 if ( fd == -1 )
2049 throwf("can't create temp file %s, errnor=%d", tempCachePath, errno);
2050
2051 // try to allocate whole cache file contiguously
2052 fstore_t fcntlSpec = { F_ALLOCATECONTIG|F_ALLOCATEALL, F_PEOFPOSMODE, 0, cacheFileSize, 0 };
2053 ::fcntl(fd, F_PREALLOCATE, &fcntlSpec);
2054
2055 // write out cache file
2056 if ( verbose )
2057 fprintf(stderr, "update_dyld_shared_cache: writing cache to disk\n");
2058 if ( ::pwrite(fd, inMemoryCache, cacheFileSize, 0) != cacheFileSize )
2059 throwf("write() failure creating cache file, errno=%d", errno);
2060 if ( progress ) {
2061 // assuming write takes 35% of time
2062 fprintf(stdout, "%3u/%u\n", (archIndex+1)*90, archCount*100);
2063 }
2064
2065 // flush to disk and close
2066 int result = ::fcntl(fd, F_FULLFSYNC, NULL);
2067 if ( result == -1 )
2068 fprintf(stderr, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno, tempCachePath);
2069 result = ::close(fd);
2070 if ( result != 0 )
2071 fprintf(stderr, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno, tempCachePath);
2072
2073 // atomically swap in new cache file, do this after F_FULLFSYNC
2074 result = ::rename(tempCachePath, fCacheFilePath);
2075 if ( result != 0 )
2076 throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath, fCacheFilePath, errno);
2077
2078 // flush everything to disk to assure rename() gets recorded
2079 ::sync();
2080 didUpdate = true;
2081
2082 // restore default signal handlers
2083 ::signal(SIGINT, SIG_DFL);
2084 ::signal(SIGBUS, SIG_DFL);
2085 ::signal(SIGSEGV, SIG_DFL);
2086
2087 // generate human readable "map" file that shows the layout of the cache file
2088 if ( verbose )
2089 fprintf(stderr, "update_dyld_shared_cache: writing .map file to disk\n");
2090 char mapFilePath[strlen(fCacheFilePath)+16];
2091 sprintf(mapFilePath, "%s.map", fCacheFilePath);
2092 char tempMapFilePath[strlen(fCacheFilePath)+32];
2093 sprintf(tempMapFilePath, "%s.map%u", fCacheFilePath, getpid());
2094 FILE* fmap = ::fopen(tempMapFilePath, "w");
2095 if ( fmap == NULL ) {
2096 fprintf(stderr, "can't create map file %s, errnor=%d", tempCachePath, errno);
2097 }
2098 else {
2099 for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
2100 const char* prot = "RW";
2101 if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_READ) )
2102 prot = "EX";
2103 else if ( it->sfm_init_prot == VM_PROT_READ )
2104 prot = "RO";
2105 else if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_WRITE|VM_PROT_READ) )
2106 prot = "WX";
2107 if ( it->sfm_size > 1024*1024 )
2108 fprintf(fmap, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/(1024*1024),
2109 it->sfm_address, it->sfm_address+it->sfm_size);
2110 else
2111 fprintf(fmap, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/1024,
2112 it->sfm_address, it->sfm_address+it->sfm_size);
2113 }
2114
2115 fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
2116 (fOffsetOfExportInfoInCombinedLinkedit-fOffsetOfWeakBindInfoInCombinedLinkedit)/1024,
2117 fLinkEditsStartAddress+fOffsetOfWeakBindInfoInCombinedLinkedit,
2118 fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit);
2119 fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
2120 (fOffsetOfBindInfoInCombinedLinkedit-fOffsetOfExportInfoInCombinedLinkedit)/1024,
2121 fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit,
2122 fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit);
2123 fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
2124 (fOffsetOfLazyBindInfoInCombinedLinkedit-fOffsetOfBindInfoInCombinedLinkedit)/1024,
2125 fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit,
2126 fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit);
2127 fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
2128 (fOffsetOfOldSymbolTableInfoInCombinedLinkedit-fOffsetOfLazyBindInfoInCombinedLinkedit)/1024,
2129 fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit,
2130 fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit);
2131 fprintf(fmap, "linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table info\n",
2132 (fLinkEditsTotalOptimizedSize-fOffsetOfOldSymbolTableInfoInCombinedLinkedit)/(1024*1024),
2133 fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit,
2134 fLinkEditsStartAddress+fLinkEditsTotalOptimizedSize);
2135
2136 for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
2137 fprintf(fmap, "%s\n", it->layout->getID().name);
2138 const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
2139 for (int i=0; i < segs.size(); ++i) {
2140 const MachOLayoutAbstraction::Segment& seg = segs[i];
2141 fprintf(fmap, "\t%16s 0x%0llX -> 0x%0llX\n", seg.name(), seg.newAddress(), seg.newAddress()+seg.size());
2142 }
2143 }
2144 if ( warnings.size() > 0 ) {
2145 fprintf(fmap, "# Warnings:\n");
2146 for (std::vector<const char*>::iterator it=warnings.begin(); it != warnings.end(); ++it) {
2147 fprintf(fmap, "# %s\n", *it);
2148 }
2149 }
2150 fclose(fmap);
2151 result = ::rename(tempMapFilePath, mapFilePath);
2152 }
2153 }
2154
2155 // free in memory cache
2156 vm_deallocate(mach_task_self(), (vm_address_t)inMemoryCache, allocatedCacheSize);
2157 inMemoryCache = NULL;
2158 if ( progress ) {
2159 // finished
2160 fprintf(stdout, "%3u/%u\n", (archIndex+1)*100, archCount*100);
2161 }
2162 }
2163 catch (...){
2164 // remove temp cache file
2165 ::unlink(tempCachePath);
2166 // remove in memory cache
2167 if ( inMemoryCache != NULL )
2168 vm_deallocate(mach_task_self(), (vm_address_t)inMemoryCache, allocatedCacheSize);
2169 throw;
2170 }
2171 }
2172 return didUpdate;
2173 }
2174
2175
2176
2177 //
2178 // The shared cache is driven by /var/db/dyld/shared_region_roots which contains
2179 // the paths used to search for dylibs that should go in the shared cache
2180 //
2181 // Leading and trailing white space is ignored
2182 // Blank lines are ignored
2183 // Lines starting with # are ignored
2184 //
2185 static void parsePathsFile(const char* filePath, std::vector<const char*>& paths)
2186 {
2187 // read in whole file
2188 int fd = open(filePath, O_RDONLY, 0);
2189 if ( fd == -1 ) {
2190 fprintf(stderr, "update_dyld_shared_cache: can't open file: %s\n", filePath);
2191 exit(1);
2192 }
2193 struct stat stat_buf;
2194 fstat(fd, &stat_buf);
2195 char* p = (char*)malloc(stat_buf.st_size);
2196 if ( p == NULL ) {
2197 fprintf(stderr, "update_dyld_shared_cache: malloc failure\n");
2198 exit(1);
2199 }
2200 if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) {
2201 fprintf(stderr, "update_dyld_shared_cache: can't read file: %s\n", filePath);
2202 exit(1);
2203 }
2204 ::close(fd);
2205
2206 // parse into paths and add to vector
2207 char * const end = &p[stat_buf.st_size];
2208 enum { lineStart, inSymbol, inComment } state = lineStart;
2209 char* symbolStart = NULL;
2210 for (char* s = p; s < end; ++s ) {
2211 switch ( state ) {
2212 case lineStart:
2213 if ( *s =='#' ) {
2214 state = inComment;
2215 }
2216 else if ( !isspace(*s) ) {
2217 state = inSymbol;
2218 symbolStart = s;
2219 }
2220 break;
2221 case inSymbol:
2222 if ( *s == '\n' ) {
2223 *s = '\0';
2224 // removing any trailing spaces
2225 char* last = s-1;
2226 while ( isspace(*last) ) {
2227 *last = '\0';
2228 --last;
2229 }
2230 paths.push_back(symbolStart);
2231 symbolStart = NULL;
2232 state = lineStart;
2233 }
2234 break;
2235 case inComment:
2236 if ( *s == '\n' )
2237 state = lineStart;
2238 break;
2239 }
2240 }
2241 // Note: we do not free() the malloc buffer, because the strings in it are used by exec()
2242 }
2243
2244
2245
2246 static void setSharedDylibs(const char* rootPath, bool usesOverlay, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
2247 {
2248 // set file system root
2249 ArchGraph::setFileSystemRoot(rootPath, usesOverlay);
2250
2251 // initialize all architectures requested
2252 for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
2253 ArchGraph::addArchPair(*a);
2254
2255 // add roots to graph
2256 for(std::vector<const char*>::const_iterator it = rootsPaths.begin(); it != rootsPaths.end(); ++it)
2257 ArchGraph::addRoot(*it, onlyArchs);
2258
2259 // determine shared dylibs
2260 for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
2261 ArchGraph::findSharedDylibs(*a);
2262 }
2263
2264
2265 static void scanForSharedDylibs(const char* rootPath, bool usesOverlay, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
2266 {
2267 char rootDirOfPathFiles[strlen(rootPath)+strlen(dirOfPathFiles)+2];
2268 // in -overlay mode, still look for roots in /var/db/dyld
2269 // in -root mode, look for roots in /rootpath/var/db/dyld
2270 if ( !usesOverlay && (strlen(rootPath) != 0) ) {
2271 strcpy(rootDirOfPathFiles, rootPath);
2272 strcat(rootDirOfPathFiles, dirOfPathFiles);
2273 dirOfPathFiles = rootDirOfPathFiles;
2274 }
2275
2276 // extract all root paths from files in "/var/db/dyld/shared_region_roots/"
2277 if ( verbose )
2278 fprintf(stderr, "update_dyld_shared_cache: finding roots in: %s\n", dirOfPathFiles);
2279 std::vector<const char*> rootsPaths;
2280 DIR* dir = ::opendir(dirOfPathFiles);
2281 if ( dir == NULL )
2282 throwf("%s does not exist, errno=%d\n", dirOfPathFiles, errno);
2283 for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
2284 if ( entry->d_type == DT_REG ) {
2285 // only look at files ending in .paths
2286 if ( strcmp(&entry->d_name[entry->d_namlen-6], ".paths") == 0 ) {
2287 char fullPath[strlen(dirOfPathFiles)+entry->d_namlen+2];
2288 strcpy(fullPath, dirOfPathFiles);
2289 strcat(fullPath, "/");
2290 strcat(fullPath, entry->d_name);
2291 parsePathsFile(fullPath, rootsPaths);
2292 }
2293 else {
2294 fprintf(stderr, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry->d_name);
2295 }
2296 }
2297 }
2298 ::closedir(dir);
2299
2300 if ( rootsPaths.size() == 0 )
2301 fprintf(stderr, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
2302 setSharedDylibs(rootPath, usesOverlay, onlyArchs, rootsPaths);
2303 }
2304
2305 static void setSharedDylibs(const char* rootPath, bool usesOverlay, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
2306 {
2307 std::vector<const char*> rootsPaths;
2308 parsePathsFile(pathsFile, rootsPaths);
2309 setSharedDylibs(rootPath, usesOverlay, onlyArchs, rootsPaths);
2310 }
2311
2312
2313 // If the 10.5.0 version of update_dyld_shared_cache was killed or crashed, it
2314 // could leave large half written cache files laying around. The function deletes
2315 // those files. To prevent the deletion of tmp files being created by another
2316 // copy of update_dyld_shared_cache, it only deletes the temp cache file if its
2317 // creation time was before the last restart of this machine.
2318 static void deleteOrphanTempCacheFiles()
2319 {
2320 DIR* dir = ::opendir(DYLD_SHARED_CACHE_DIR);
2321 if ( dir != NULL ) {
2322 std::vector<const char*> filesToDelete;
2323 for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
2324 if ( entry->d_type == DT_REG ) {
2325 // only look at files with .tmp in name
2326 if ( strstr(entry->d_name, ".tmp") != NULL ) {
2327 char fullPath[strlen(DYLD_SHARED_CACHE_DIR)+entry->d_namlen+2];
2328 strcpy(fullPath, DYLD_SHARED_CACHE_DIR);
2329 strcat(fullPath, "/");
2330 strcat(fullPath, entry->d_name);
2331 struct stat tmpFileStatInfo;
2332 if ( stat(fullPath, &tmpFileStatInfo) != -1 ) {
2333 int mib[2] = {CTL_KERN, KERN_BOOTTIME};
2334 struct timeval boottime;
2335 size_t size = sizeof(boottime);
2336 if ( (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) && (boottime.tv_sec != 0) ) {
2337 // make sure this file is older than the boot time of this machine
2338 if ( tmpFileStatInfo.st_mtime < boottime.tv_sec ) {
2339 filesToDelete.push_back(strdup(fullPath));
2340 }
2341 }
2342 }
2343 }
2344 }
2345 }
2346 ::closedir(dir);
2347 for(std::vector<const char*>::iterator it = filesToDelete.begin(); it != filesToDelete.end(); ++it) {
2348 fprintf(stderr, "update_dyld_shared_cache: deleting old temp cache file: %s\n", *it);
2349 ::unlink(*it);
2350 }
2351 }
2352 }
2353
2354
2355
2356 static bool updateSharedeCacheFile(const char* rootPath, bool usesOverlay, const char* cacheDir, const std::set<ArchPair>& onlyArchs,
2357 bool force, bool alphaSort, bool optimize, bool deleteExistingFirst, bool verify, bool keepSignatures)
2358 {
2359 bool didUpdate = false;
2360 // get dyld load address info
2361 UniversalMachOLayout* dyldLayout = NULL;
2362 char dyldPath[1024];
2363 strlcpy(dyldPath, rootPath, 1024);
2364 strlcat(dyldPath, "/usr/lib/dyld", 1024);
2365 struct stat stat_buf;
2366 if ( stat(dyldPath, &stat_buf) == 0 ) {
2367 dyldLayout = new UniversalMachOLayout(dyldPath, &onlyArchs);
2368 }
2369 else {
2370 dyldLayout = new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs);
2371 }
2372 const int archCount = onlyArchs.size();
2373 int index = 0;
2374 for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a, ++index) {
2375 const MachOLayoutAbstraction* dyldLayoutForArch = dyldLayout->getSlice(*a);
2376 uint64_t dyldBaseAddress = 0;
2377 if ( dyldLayoutForArch != NULL )
2378 dyldBaseAddress = dyldLayoutForArch->getBaseAddress();
2379 else
2380 fprintf(stderr, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
2381 switch ( a->arch ) {
2382 case CPU_TYPE_POWERPC:
2383 {
2384 #if __i386__ || __x86_64__
2385 // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
2386 SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, false, usesOverlay, dyldBaseAddress);
2387 didUpdate |= cache.update(usesOverlay, force, false, deleteExistingFirst, index, archCount, keepSignatures);
2388 #else
2389 SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
2390 didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
2391 #endif
2392 }
2393 break;
2394 case CPU_TYPE_I386:
2395 {
2396 SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
2397 didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
2398 }
2399 break;
2400 case CPU_TYPE_X86_64:
2401 {
2402 SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
2403 didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
2404 }
2405 break;
2406 case CPU_TYPE_ARM:
2407 {
2408 SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
2409 didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
2410 }
2411 break;
2412 }
2413 }
2414
2415 deleteOrphanTempCacheFiles();
2416
2417 return didUpdate;
2418 }
2419
2420
2421 static void usage()
2422 {
2423 fprintf(stderr, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
2424 }
2425
2426
2427 int main(int argc, const char* argv[])
2428 {
2429 std::set<ArchPair> onlyArchs;
2430 const char* rootPath = "";
2431 const char* dylibListFile = NULL;
2432 bool force = false;
2433 bool alphaSort = false;
2434 bool optimize = true;
2435 bool hasRoot = false;
2436 bool hasOverlay = false;
2437 bool verify = false;
2438 bool keepSignatures = false;
2439
2440 try {
2441 // parse command line options
2442 for(int i=1; i < argc; ++i) {
2443 const char* arg = argv[i];
2444 if ( arg[0] == '-' ) {
2445 if ( strcmp(arg, "-debug") == 0 ) {
2446 verbose = true;
2447 }
2448 else if ( strcmp(arg, "-force") == 0 ) {
2449 force = true;
2450 }
2451 else if ( strcmp(arg, "-verify") == 0 ) {
2452 verify = true;
2453 }
2454 else if ( strcmp(arg, "-sort_by_name") == 0 ) {
2455 alphaSort = true;
2456 }
2457 else if ( strcmp(arg, "-progress") == 0 ) {
2458 progress = true;
2459 }
2460 else if ( strcmp(arg, "-opt") == 0 ) {
2461 optimize = true;
2462 }
2463 else if ( strcmp(arg, "-no_opt") == 0 ) {
2464 optimize = false;
2465 }
2466 else if ( strcmp(arg, "-dylib_list") == 0 ) {
2467 dylibListFile = argv[++i];
2468 if ( dylibListFile == NULL )
2469 throw "-dylib_list missing path argument";
2470 keepSignatures = true;
2471 }
2472 else if ( (strcmp(arg, "-root") == 0) || (strcmp(arg, "--root") == 0) ) {
2473 if ( hasOverlay )
2474 throw "cannot use both -root and -overlay";
2475 rootPath = argv[++i];
2476 if ( rootPath == NULL )
2477 throw "-root missing path argument";
2478 hasRoot = true;
2479 }
2480 else if ( strcmp(arg, "-overlay") == 0 ) {
2481 if ( hasRoot )
2482 throw "cannot use both -root and -overlay";
2483 rootPath = argv[++i];
2484 if ( rootPath == NULL )
2485 throw "-root missing path argument";
2486 hasOverlay = true;
2487 }
2488 else if ( strcmp(arg, "-arch") == 0 ) {
2489 const char* arch = argv[++i];
2490 if ( strcmp(arch, "ppc") == 0 )
2491 onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
2492 else if ( strcmp(arch, "i386") == 0 )
2493 onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
2494 else if ( strcmp(arch, "x86_64") == 0 )
2495 onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
2496 else if ( strcmp(arch, "armv4t") == 0 )
2497 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V4T));
2498 else if ( strcmp(arch, "armv5") == 0 )
2499 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V5TEJ));
2500 else if ( strcmp(arch, "armv6") == 0 )
2501 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6));
2502 else if ( strcmp(arch, "armv7") == 0 )
2503 onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7));
2504 else
2505 throwf("unknown architecture %s", arch);
2506 }
2507 else if ( strcmp(arg, "-universal_boot") == 0 ) {
2508 #if __ppc__
2509 throwf("universal_boot option can only be used on Intel machines");
2510 #endif
2511 onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
2512 onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
2513 }
2514 else {
2515 usage();
2516 throwf("unknown option: %s\n", arg);
2517 }
2518 }
2519 else {
2520 usage();
2521 throwf("unknown option: %s\n", arg);
2522 }
2523 }
2524
2525 // strip tailing slashes on -root or -overlay
2526 if ( rootPath[0] != '\0' ) {
2527 int len = strlen(rootPath)-1;
2528 if ( rootPath[len] == '/' ) {
2529 char* newRootPath = strdup(rootPath);
2530 while ( newRootPath[len] == '/' )
2531 newRootPath[len--] = '\0';
2532 rootPath = newRootPath;
2533 }
2534 }
2535
2536 // if no restrictions specified, use architectures that work on this machine
2537 if ( onlyArchs.size() == 0 ) {
2538 int available;
2539 size_t len = sizeof(int);
2540 #if __i386__ || __x86_64__
2541 onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
2542 // check rosetta is installed
2543 char rosettaPath[1024];
2544 strlcpy(rosettaPath, rootPath, 1024);
2545 strlcat(rosettaPath, "/usr/libexec/oah/translate", 1024);
2546 struct stat stat_buf;
2547 if ( stat(rosettaPath, &stat_buf) == 0 ) {
2548 onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
2549 }
2550 else if ( hasOverlay ) {
2551 // in overlay mode, rosetta may be installed on base system, but is not in update root
2552 if ( stat("/usr/libexec/oah/translate", &stat_buf) == 0 )
2553 onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
2554 }
2555 // check system is capable of running 64-bit programs
2556 if ( (sysctlbyname("hw.optional.x86_64", &available, &len, NULL, 0) == 0) && available )
2557 onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
2558 #else
2559 #error unknown architecture
2560 #endif
2561 }
2562
2563 if ( !verify && (geteuid() != 0) )
2564 throw "you must be root to run this tool";
2565
2566 // build list of shared dylibs
2567 if ( dylibListFile != NULL )
2568 setSharedDylibs(rootPath, hasOverlay, dylibListFile, onlyArchs);
2569 else
2570 scanForSharedDylibs(rootPath, hasOverlay, "/var/db/dyld/shared_region_roots/", onlyArchs);
2571 updateSharedeCacheFile(rootPath, hasOverlay, DYLD_SHARED_CACHE_DIR, onlyArchs, force, alphaSort, optimize,
2572 false, verify, keepSignatures);
2573 }
2574 catch (const char* msg) {
2575 fprintf(stderr, "update_dyld_shared_cache failed: %s\n", msg);
2576 return 1;
2577 }
2578
2579 return 0;
2580 }
2581
2582
2583