]> git.saurik.com Git - apple/dyld.git/blob - dyld3/shared-cache/DyldSharedCache.h
dyld-733.8.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
44 namespace objc_opt {
45 struct objc_opt_t;
46 }
47
48 class VIS_HIDDEN DyldSharedCache
49 {
50 public:
51
52 #if BUILDING_CACHE_BUILDER
53 enum CodeSigningDigestMode
54 {
55 SHA256only = 0,
56 SHA1only = 1,
57 Agile = 2
58 };
59
60 struct CreateOptions
61 {
62 std::string outputFilePath;
63 std::string outputMapFilePath;
64 const dyld3::GradedArchs* archs;
65 dyld3::Platform platform;
66 bool excludeLocalSymbols;
67 bool optimizeStubs;
68 bool optimizeObjC;
69 CodeSigningDigestMode codeSigningDigestMode;
70 bool dylibsRemovedDuringMastering;
71 bool inodesAreSameAsRuntime;
72 bool cacheSupportsASLR;
73 bool forSimulator;
74 bool isLocallyBuiltCache;
75 bool verbose;
76 bool evictLeafDylibsOnOverflow;
77 std::unordered_map<std::string, unsigned> dylibOrdering;
78 std::unordered_map<std::string, unsigned> dirtyDataSegmentOrdering;
79 std::string loggingPrefix;
80 };
81
82 struct MappedMachO
83 {
84 MappedMachO()
85 : mh(nullptr), length(0), isSetUID(false), protectedBySIP(false), sliceFileOffset(0), modTime(0), inode(0) { }
86 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)
87 : runtimePath(path), mh(p), length(l), isSetUID(isu), protectedBySIP(sip), sliceFileOffset(o), modTime(m), inode(i) { }
88
89 std::string runtimePath;
90 const dyld3::MachOAnalyzer* mh;
91 size_t length;
92 uint64_t isSetUID : 1,
93 protectedBySIP : 1,
94 sliceFileOffset : 62;
95 uint64_t modTime; // only recorded if inodesAreSameAsRuntime
96 uint64_t inode; // only recorded if inodesAreSameAsRuntime
97 };
98
99 struct CreateResults
100 {
101 std::string errorMessage;
102 std::set<std::string> warnings;
103 std::set<const dyld3::MachOAnalyzer*> evictions;
104 bool agileSignature = false;
105 std::string cdHashFirst;
106 std::string cdHashSecond;
107 };
108
109
110 struct FileAlias
111 {
112 std::string realPath;
113 std::string aliasPath;
114 };
115
116
117 // This function verifies the set of dylibs that will go into the cache are self contained. That the depend on no dylibs
118 // outset the set. It will call back the loader function to try to find any mising dylibs.
119 static bool verifySelfContained(std::vector<MappedMachO>& dylibsToCache,
120 std::unordered_set<std::string>& badZippered,
121 MappedMachO (^loader)(const std::string& runtimePath), std::vector<std::pair<DyldSharedCache::MappedMachO, std::set<std::string>>>& excluded);
122
123
124 //
125 // This function is single threaded and creates a shared cache. The cache file is created in-memory.
126 //
127 // Inputs:
128 // options: various per-platform flags
129 // dylibsToCache: a list of dylibs to include in the cache
130 // otherOsDylibs: a list of other OS dylibs and bundle which should have load info added to the cache
131 // osExecutables: a list of main executables which should have closures created in the cache
132 //
133 // Returns:
134 // On success:
135 // cacheContent: start of the allocated cache buffer which must be vm_deallocated after the caller writes out the buffer.
136 // cacheLength: size of the allocated cache buffer
137 // cdHash: hash of the code directory of the code blob of the created cache
138 // warnings: all warning messsages generated during the creation of the cache
139 //
140 // On failure:
141 // cacheContent: nullptr
142 // errorMessage: the string describing why the cache could not be created
143 // warnings: all warning messsages generated before the failure
144 //
145 static CreateResults create(const CreateOptions& options,
146 const dyld3::closure::FileSystem& fileSystem,
147 const std::vector<MappedMachO>& dylibsToCache,
148 const std::vector<MappedMachO>& otherOsDylibs,
149 const std::vector<MappedMachO>& osExecutables);
150
151
152 //
153 // Returns a text "map" file as a big string
154 //
155 std::string mapFile() const;
156
157 #endif // TARGET_OS_OSX
158
159
160 //
161 // Returns the architecture name of the shared cache, e.g. "arm64"
162 //
163 const char* archName() const;
164
165
166 //
167 // Returns the platform the cache is for
168 //
169 dyld3::Platform platform() const;
170
171
172 //
173 // Iterates over each dylib in the cache
174 //
175 void forEachImage(void (^handler)(const mach_header* mh, const char* installName)) const;
176
177
178 //
179 // Searches cache for dylib with specified path
180 //
181 bool hasImagePath(const char* dylibPath, uint32_t& imageIndex) const;
182
183
184 //
185 // Path is to a dylib in the cache and this is an optimized cache so that path cannot be overridden
186 //
187 bool hasNonOverridablePath(const char* dylibPath) const;
188
189
190 //
191 // Searches cache for dylib with specified mach_header
192 //
193 bool findMachHeaderImageIndex(const mach_header* mh, uint32_t& imageIndex) const;
194
195 //
196 // Iterates over each dylib in the cache
197 //
198 void forEachImageEntry(void (^handler)(const char* path, uint64_t mTime, uint64_t inode)) const;
199
200
201 //
202 // Iterates over each dylib in the cache
203 //
204 const mach_header* getIndexedImageEntry(uint32_t index, uint64_t& mTime, uint64_t& node) const;
205
206
207 //
208 // Iterates over each dylib in the cache
209 //
210 void forEachImageTextSegment(void (^handler)(uint64_t loadAddressUnslid, uint64_t textSegmentSize, const uuid_t dylibUUID, const char* installName, bool& stop)) const;
211
212
213 //
214 // Iterates over each of the three regions in the cache
215 //
216 void forEachRegion(void (^handler)(const void* content, uint64_t vmAddr, uint64_t size, uint32_t permissions)) const;
217
218
219 //
220 // Returns if an address range is in this cache, and if so if in a read-only area
221 //
222 bool inCache(const void* addr, size_t length, bool& readOnly) const;
223
224
225 //
226 // returns address the cache would load at if unslid
227 //
228 uint64_t unslidLoadAddress() const;
229
230
231 //
232 // returns UUID of cache
233 //
234 void getUUID(uuid_t uuid) const;
235
236
237 //
238 // returns the vm size required to map cache
239 //
240 uint64_t mappedSize() const;
241
242
243 //
244 // searches cache for pre-built closure for program
245 //
246 const dyld3::closure::LaunchClosure* findClosure(const char* executablePath) const;
247
248
249 //
250 // iterates all pre-built closures for program
251 //
252 void forEachLaunchClosure(void (^handler)(const char* executableRuntimePath, const dyld3::closure::LaunchClosure* closure)) const;
253
254
255 //
256 // iterates all pre-built Image* for OS dylibs/bundles not in dyld cache
257 //
258 void forEachDlopenImage(void (^handler)(const char* runtimePath, const dyld3::closure::Image* image)) const;
259
260
261 //
262 // returns the ImageArray pointer to Images in dyld shared cache
263 //
264 const dyld3::closure::ImageArray* cachedDylibsImageArray() const;
265
266
267 //
268 // returns the ImageArray pointer to Images in OS with pre-build dlopen closure
269 //
270 const dyld3::closure::ImageArray* otherOSImageArray() const;
271
272
273 //
274 // searches cache for pre-built dlopen closure for OS dylib/bundle
275 //
276 const dyld3::closure::Image* findDlopenOtherImage(const char* path) const;
277
278 //
279 // Returns the pointer to the slide info for this cache
280 //
281 const dyld_cache_slide_info* slideInfo() const;
282
283 //
284 // Returns a pointer to the start of the __DATA region in the cache
285 //
286 const uint8_t* dataRegionStart() const;
287
288 //
289 // Returns a pointer to the shared cache optimized Objective-C data structures
290 //
291 const objc_opt::objc_opt_t* objcOpt() const;
292
293 //
294 // Returns a pointer to the shared cache optimized Objective-C pointer structures
295 //
296 const void* objcOptPtrs() const;
297
298
299 //
300 // returns true if the offset is in the TEXT of some cached dylib and sets *index to the dylib index
301 //
302 bool addressInText(uint32_t cacheOffset, uint32_t* index) const;
303
304 uint32_t patchableExportCount(uint32_t imageIndex) const;
305 void forEachPatchableExport(uint32_t imageIndex, void (^handler)(uint32_t cacheOffsetOfImpl, const char* exportName)) const;
306 void forEachPatchableUseOfExport(uint32_t imageIndex, uint32_t cacheOffsetOfImpl,
307 void (^handler)(dyld_cache_patchable_location patchLocation)) const;
308
309 // Helper to get the addend for a patch location since we don't want to put C++ in the shared cache format header
310 static uint64_t getAddend(const dyld_cache_patchable_location& loc) {
311 uint64_t unsingedAddend = loc.addend;
312 int64_t signedAddend = (int64_t)unsingedAddend;
313 signedAddend = (signedAddend << 52) >> 52;
314 return (uint64_t)signedAddend;
315 }
316 // Helper to get the key nam for a patch location since we don't want to put C++ in the shared cache format header
317 static const char* keyName(const dyld_cache_patchable_location& patchLocation) {
318 dyld3::MachOLoaded::ChainedFixupPointerOnDisk dummy;
319 dummy.arm64e.authRebase.auth = 1;
320 dummy.arm64e.authRebase.bind = 0;
321 dummy.arm64e.authRebase.key = patchLocation.key;
322 return dummy.arm64e.keyName();
323 }
324
325 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
326 // MRM map file generator
327 std::string generateJSONMap(const char* disposition) const;
328
329 // This generates a JSON representation of deep reverse dependency information in the cache.
330 // For each dylib, the output will contain the list of all the other dylibs transitively
331 // dependening on that library. (For example, the entry for libsystem will contain almost
332 // all of the dylibs in the cache ; a very high-level framework such as ARKit will have way
333 // fewer dependents).
334 // This is used by the shared cache ordering script to put "deep" dylibs used by everybody
335 // closer to the center of the cache.
336 std::string generateJSONDependents() const;
337 #endif
338
339 dyld_cache_header header;
340
341 private:
342 // Returns a variable of type "const T" which corresponds to the header field with the given unslid address
343 template<typename T>
344 const T getAddrField(uint64_t addr) const;
345
346 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
347 void fillMachOAnalyzersMap(std::unordered_map<std::string,dyld3::MachOAnalyzer*> & dylibAnalyzers) const;
348 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;
349 void computeReverseDependencyMap(std::unordered_map<std::string, std::set<std::string>> &reverseDependencyMap) const;
350 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;
351 void computeTransitiveDependents(std::unordered_map<std::string, std::set<std::string>> & transitiveDependents) const;
352 #endif
353 };
354
355
356
357
358
359
360
361
362 #endif /* DyldSharedCache_h */