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