dyld-851.27.tar.gz
[apple/dyld.git] / dyld3 / shared-cache / DyldSharedCache.h
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #ifndef DyldSharedCache_h
26 #define DyldSharedCache_h
27
28 #include <TargetConditionals.h>
29 #include <uuid/uuid.h>
30
31 #if (BUILDING_LIBDYLD || BUILDING_DYLD)
32 #include <sys/types.h>
33 #endif
34
35 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
36 #include <set>
37 #include <string>
38 #include <vector>
39 #include <unordered_map>
40 #include <unordered_set>
41 #endif
42
43 #include "dyld_cache_format.h"
44 #include "Diagnostics.h"
45 #include "MachOAnalyzer.h"
46 #include "Closure.h"
47 #include "JSON.h"
48
49 namespace objc_opt {
50 struct objc_opt_t;
51 }
52
53 class VIS_HIDDEN DyldSharedCache
54 {
55 public:
56
57 #if BUILDING_CACHE_BUILDER
58 enum CodeSigningDigestMode
59 {
60 SHA256only = 0,
61 SHA1only = 1,
62 Agile = 2
63 };
64
65 enum class LocalSymbolsMode {
66 keep,
67 unmap,
68 strip
69 };
70
71 struct CreateOptions
72 {
73 std::string outputFilePath;
74 std::string outputMapFilePath;
75 const dyld3::GradedArchs* archs;
76 dyld3::Platform platform;
77 LocalSymbolsMode localSymbolMode;
78 bool optimizeStubs;
79 bool optimizeDyldDlopens;
80 bool optimizeDyldLaunches;
81 CodeSigningDigestMode codeSigningDigestMode;
82 bool dylibsRemovedDuringMastering;
83 bool inodesAreSameAsRuntime;
84 bool cacheSupportsASLR;
85 bool forSimulator;
86 bool isLocallyBuiltCache;
87 bool verbose;
88 bool evictLeafDylibsOnOverflow;
89 std::unordered_map<std::string, unsigned> dylibOrdering;
90 std::unordered_map<std::string, unsigned> dirtyDataSegmentOrdering;
91 dyld3::json::Node objcOptimizations;
92 std::string loggingPrefix;
93 };
94
95 struct MappedMachO
96 {
97 MappedMachO()
98 : mh(nullptr), length(0), isSetUID(false), protectedBySIP(false), sliceFileOffset(0), modTime(0), inode(0) { }
99 MappedMachO(const std::string& path, const dyld3::MachOAnalyzer* p, size_t l, bool isu, bool sip, uint64_t o, uint64_t m, uint64_t i)
100 : runtimePath(path), mh(p), length(l), isSetUID(isu), protectedBySIP(sip), sliceFileOffset(o), modTime(m), inode(i) { }
101
102 std::string runtimePath;
103 const dyld3::MachOAnalyzer* mh;
104 size_t length;
105 uint64_t isSetUID : 1,
106 protectedBySIP : 1,
107 sliceFileOffset : 62;
108 uint64_t modTime; // only recorded if inodesAreSameAsRuntime
109 uint64_t inode; // only recorded if inodesAreSameAsRuntime
110 };
111
112 struct CreateResults
113 {
114 std::string errorMessage;
115 std::set<std::string> warnings;
116 std::set<const dyld3::MachOAnalyzer*> evictions;
117 bool agileSignature = false;
118 std::string cdHashFirst;
119 std::string cdHashSecond;
120 };
121
122
123 struct FileAlias
124 {
125 std::string realPath;
126 std::string aliasPath;
127 };
128
129
130 // This function verifies the set of dylibs that will go into the cache are self contained. That the depend on no dylibs
131 // outset the set. It will call back the loader function to try to find any mising dylibs.
132 static bool verifySelfContained(std::vector<MappedMachO>& dylibsToCache,
133 std::unordered_set<std::string>& badZippered,
134 MappedMachO (^loader)(const std::string& runtimePath, Diagnostics& diag), std::vector<std::pair<DyldSharedCache::MappedMachO, std::set<std::string>>>& excluded);
135
136
137 //
138 // This function is single threaded and creates a shared cache. The cache file is created in-memory.
139 //
140 // Inputs:
141 // options: various per-platform flags
142 // dylibsToCache: a list of dylibs to include in the cache
143 // otherOsDylibs: a list of other OS dylibs and bundle which should have load info added to the cache
144 // osExecutables: a list of main executables which should have closures created in the cache
145 //
146 // Returns:
147 // On success:
148 // cacheContent: start of the allocated cache buffer which must be vm_deallocated after the caller writes out the buffer.
149 // cacheLength: size of the allocated cache buffer
150 // cdHash: hash of the code directory of the code blob of the created cache
151 // warnings: all warning messsages generated during the creation of the cache
152 //
153 // On failure:
154 // cacheContent: nullptr
155 // errorMessage: the string describing why the cache could not be created
156 // warnings: all warning messsages generated before the failure
157 //
158 static CreateResults create(const CreateOptions& options,
159 const dyld3::closure::FileSystem& fileSystem,
160 const std::vector<MappedMachO>& dylibsToCache,
161 const std::vector<MappedMachO>& otherOsDylibs,
162 const std::vector<MappedMachO>& osExecutables);
163
164
165 //
166 // Returns a text "map" file as a big string
167 //
168 std::string mapFile() const;
169
170 #endif // BUILDING_CACHE_BUILDER
171
172
173 //
174 // Returns the architecture name of the shared cache, e.g. "arm64"
175 //
176 const char* archName() const;
177
178
179 //
180 // Returns the platform the cache is for
181 //
182 dyld3::Platform platform() const;
183
184
185 //
186 // Iterates over each dylib in the cache
187 //
188 void forEachImage(void (^handler)(const mach_header* mh, const char* installName)) const;
189
190
191 //
192 // Searches cache for dylib with specified path
193 //
194 bool hasImagePath(const char* dylibPath, uint32_t& imageIndex) const;
195
196
197 //
198 // Is this path (which we know is in the shared cache), overridable
199 //
200 bool isOverridablePath(const char* dylibPath) const;
201
202
203 //
204 // Path is to a dylib in the cache and this is an optimized cache so that path cannot be overridden
205 //
206 bool hasNonOverridablePath(const char* dylibPath) const;
207
208
209 //
210 // Check if shared cache contains local symbols info
211 //
212 const bool hasLocalSymbolsInfo() const;
213
214
215 //
216 // Get code signature mapped address
217 //
218 uint64_t getCodeSignAddress() const;
219
220
221 //
222 // Searches cache for dylib with specified mach_header
223 //
224 bool findMachHeaderImageIndex(const mach_header* mh, uint32_t& imageIndex) const;
225
226 //
227 // Iterates over each dylib in the cache
228 //
229 void forEachImageEntry(void (^handler)(const char* path, uint64_t mTime, uint64_t inode)) const;
230
231
232 //
233 // Get image entry from index
234 //
235 const mach_header* getIndexedImageEntry(uint32_t index, uint64_t& mTime, uint64_t& node) const;
236
237
238 // iterates over all dylibs and aliases
239 void forEachDylibPath(void (^handler)(const char* dylibPath, uint32_t index)) const;
240
241
242 //
243 // Get image path from index
244 //
245 const char* getIndexedImagePath(uint32_t index) const;
246
247 #if BUILDING_LIBDYLD
248 //
249 // Get the canonical (dylib) path for a given path, which may be a symlink to something in the cache
250 //
251 const char* getCanonicalPath(const char* path) const;
252 #endif
253
254 //
255 // Iterates over each text segment in the cache
256 //
257 void forEachImageTextSegment(void (^handler)(uint64_t loadAddressUnslid, uint64_t textSegmentSize, const uuid_t dylibUUID, const char* installName, bool& stop)) const;
258
259
260 //
261 // Iterates over each of the three regions in the cache
262 //
263 void forEachRegion(void (^handler)(const void* content, uint64_t vmAddr, uint64_t size,
264 uint32_t initProt, uint32_t maxProt, uint64_t flags)) const;
265
266
267 //
268 // Get local symbols nlist entries
269 //
270 const void* getLocalNlistEntries() const;
271
272
273 //
274 // Get local symbols nlist count
275 //
276 const uint32_t getLocalNlistCount() const;
277
278
279 //
280 // Get local symbols strings
281 //
282 const char* getLocalStrings() const;
283
284
285 //
286 // Get local symbols strings size
287 //
288 const uint32_t getLocalStringsSize() const;
289
290
291 //
292 // Iterates over each local symbol entry in the cache
293 //
294 void forEachLocalSymbolEntry(void (^handler)(uint32_t dylibOffset, uint32_t nlistStartIndex, uint32_t nlistCount, bool& stop)) const;
295
296 //
297 // Returns if an address range is in this cache, and if so if in a read-only area
298 //
299 bool inCache(const void* addr, size_t length, bool& readOnly) const;
300
301 //
302 // Returns true if a path is an alternate path (symlink)
303 //
304 bool isAlias(const char* path) const;
305
306 //
307 // returns address the cache would load at if unslid
308 //
309 uint64_t unslidLoadAddress() const;
310
311
312 //
313 // returns UUID of cache
314 //
315 void getUUID(uuid_t uuid) const;
316
317
318 //
319 // returns the vm size required to map cache
320 //
321 uint64_t mappedSize() const;
322
323
324 //
325 // searches cache for pre-built closure for program
326 //
327 const dyld3::closure::LaunchClosure* findClosure(const char* executablePath) const;
328
329
330 //
331 // iterates all pre-built closures for program
332 //
333 void forEachLaunchClosure(void (^handler)(const char* executableRuntimePath, const dyld3::closure::LaunchClosure* closure)) const;
334
335
336 //
337 // iterates all pre-built Image* for OS dylibs/bundles not in dyld cache
338 //
339 void forEachDlopenImage(void (^handler)(const char* runtimePath, const dyld3::closure::Image* image)) const;
340
341
342 //
343 // returns the ImageArray pointer to Images in dyld shared cache
344 //
345 const dyld3::closure::ImageArray* cachedDylibsImageArray() const;
346
347
348 //
349 // returns the ImageArray pointer to Images in OS with pre-build dlopen closure
350 //
351 const dyld3::closure::ImageArray* otherOSImageArray() const;
352
353
354 //
355 // searches cache for pre-built dlopen closure for OS dylib/bundle
356 //
357 const dyld3::closure::Image* findDlopenOtherImage(const char* path) const;
358
359 //
360 // Returns the pointer to the slide info for this cache
361 //
362 const dyld_cache_slide_info* legacyCacheSlideInfo() const;
363
364 //
365 // Returns a pointer to the __DATA region mapping in the cache
366 //
367 const dyld_cache_mapping_info* legacyCacheDataRegionMapping() const;
368
369 //
370 // Returns a pointer to the start of the __DATA region in the cache
371 //
372 const uint8_t* legacyCacheDataRegionBuffer() const;
373
374 //
375 // Returns a pointer to the shared cache optimized Objective-C data structures
376 //
377 const objc_opt::objc_opt_t* objcOpt() const;
378
379 //
380 // Returns a pointer to the shared cache optimized Objective-C pointer structures
381 //
382 const void* objcOptPtrs() const;
383
384 // Returns true if the cache has any slide info, either old style on a single data region
385 // or on each individual data mapping
386 bool hasSlideInfo() const;
387
388 void forEachSlideInfo(void (^handler)(uint64_t mappingStartAddress, uint64_t mappingSize,
389 const uint8_t* mappingPagesStart,
390 uint64_t slideInfoOffset, uint64_t slideInfoSize,
391 const dyld_cache_slide_info* slideInfoHeader)) const;
392
393
394 //
395 // returns true if the offset is in the TEXT of some cached dylib and sets *index to the dylib index
396 //
397 bool addressInText(uint32_t cacheOffset, uint32_t* index) const;
398
399 uint32_t patchableExportCount(uint32_t imageIndex) const;
400 void forEachPatchableExport(uint32_t imageIndex, void (^handler)(uint32_t cacheOffsetOfImpl, const char* exportName)) const;
401 void forEachPatchableUseOfExport(uint32_t imageIndex, uint32_t cacheOffsetOfImpl,
402 void (^handler)(dyld_cache_patchable_location patchLocation)) const;
403
404 // Helper to get the addend for a patch location since we don't want to put C++ in the shared cache format header
405 static uint64_t getAddend(const dyld_cache_patchable_location& loc) {
406 uint64_t unsingedAddend = loc.addend;
407 int64_t signedAddend = (int64_t)unsingedAddend;
408 signedAddend = (signedAddend << 52) >> 52;
409 return (uint64_t)signedAddend;
410 }
411 // Helper to get the key nam for a patch location since we don't want to put C++ in the shared cache format header
412 static const char* keyName(const dyld_cache_patchable_location& patchLocation) {
413 dyld3::MachOLoaded::ChainedFixupPointerOnDisk dummy;
414 dummy.arm64e.authRebase.auth = 1;
415 dummy.arm64e.authRebase.bind = 0;
416 dummy.arm64e.authRebase.key = patchLocation.key;
417 return dummy.arm64e.keyName();
418 }
419
420 #if (BUILDING_LIBDYLD || BUILDING_DYLD)
421
422 typedef void (*DataConstLogFunc)(const char*, ...) __attribute__((format(printf, 1, 2)));
423 void changeDataConstPermissions(mach_port_t machTask, uint32_t permissions, DataConstLogFunc logFunc) const;
424
425 struct DataConstLazyScopedWriter {
426 DataConstLazyScopedWriter(const DyldSharedCache* cache, mach_port_t machTask, DataConstLogFunc logFunc);
427 ~DataConstLazyScopedWriter();
428
429 // Delete all other kinds of constructors to make sure we don't accidentally copy these around
430 DataConstLazyScopedWriter() = delete;
431 DataConstLazyScopedWriter(const DataConstLazyScopedWriter&) = delete;
432 DataConstLazyScopedWriter(DataConstLazyScopedWriter&&) = delete;
433 DataConstLazyScopedWriter& operator=(const DataConstLazyScopedWriter&) = delete;
434 DataConstLazyScopedWriter& operator=(DataConstLazyScopedWriter&&) = delete;
435
436 void makeWriteable();
437
438 const DyldSharedCache* cache = nullptr;
439 mach_port_t machTask = MACH_PORT_NULL;
440 DataConstLogFunc logFunc = nullptr;
441 bool wasMadeWritable = false;
442 };
443
444 struct DataConstScopedWriter {
445 DataConstScopedWriter(const DyldSharedCache* cache, mach_port_t machTask, DataConstLogFunc logFunc);
446 ~DataConstScopedWriter() = default;
447
448 // Delete all other kinds of constructors to make sure we don't accidentally copy these around
449 DataConstScopedWriter() = delete;
450 DataConstScopedWriter(const DataConstScopedWriter&) = delete;
451 DataConstScopedWriter(DataConstScopedWriter&&) = delete;
452 DataConstScopedWriter& operator=(const DataConstScopedWriter&) = delete;
453 DataConstScopedWriter& operator=(DataConstScopedWriter&&) = delete;
454
455 DataConstLazyScopedWriter writer;
456 };
457 #endif
458
459 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
460 // MRM map file generator
461 std::string generateJSONMap(const char* disposition) const;
462
463 // This generates a JSON representation of deep reverse dependency information in the cache.
464 // For each dylib, the output will contain the list of all the other dylibs transitively
465 // dependening on that library. (For example, the entry for libsystem will contain almost
466 // all of the dylibs in the cache ; a very high-level framework such as ARKit will have way
467 // fewer dependents).
468 // This is used by the shared cache ordering script to put "deep" dylibs used by everybody
469 // closer to the center of the cache.
470 std::string generateJSONDependents() const;
471 #endif
472
473 // Note these enum entries are only valid for 64-bit archs.
474 enum class ConstantClasses {
475 cfStringAtomSize = 32
476 };
477
478 // Returns the start and size of the range in the shared cache of the ObjC constants, such as
479 // all of the CFString's which have been moved in to a contiguous range
480 std::pair<const void*, uint64_t> getObjCConstantRange() const;
481
482 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
483 dyld3::MachOAnalyzer::VMAddrConverter makeVMAddrConverter(bool contentRebased) const;
484 #endif
485
486 dyld_cache_header header;
487
488 // The most mappings we could generate.
489 // For now its __TEXT, __DATA_CONST, __DATA_DIRTY, __DATA, __LINKEDIT,
490 // and optionally also __AUTH, __AUTH_CONST, __AUTH_DIRTY
491 static const uint32_t MaxMappings = 8;
492
493 private:
494 // Returns a variable of type "const T" which corresponds to the header field with the given unslid address
495 template<typename T>
496 const T getAddrField(uint64_t addr) const;
497
498 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
499 void fillMachOAnalyzersMap(std::unordered_map<std::string,dyld3::MachOAnalyzer*> & dylibAnalyzers) const;
500 void computeReverseDependencyMapForDylib(std::unordered_map<std::string, std::set<std::string>> &reverseDependencyMap, const std::unordered_map<std::string,dyld3::MachOAnalyzer*> & dylibAnalyzers, const std::string &loadPath) const;
501 void computeReverseDependencyMap(std::unordered_map<std::string, std::set<std::string>> &reverseDependencyMap) const;
502 void findDependentsRecursively(std::unordered_map<std::string, std::set<std::string>> &transitiveDependents, const std::unordered_map<std::string, std::set<std::string>> &reverseDependencyMap, std::set<std::string> & visited, const std::string &loadPath) const;
503 void computeTransitiveDependents(std::unordered_map<std::string, std::set<std::string>> & transitiveDependents) const;
504 #endif
505 };
506
507
508
509
510
511
512
513
514 #endif /* DyldSharedCache_h */