2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #ifndef DyldSharedCache_h
26 #define DyldSharedCache_h
28 #include <TargetConditionals.h>
29 #include <uuid/uuid.h>
31 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
35 #include <unordered_map>
36 #include <unordered_set>
39 #include "dyld_cache_format.h"
40 #include "Diagnostics.h"
41 #include "MachOAnalyzer.h"
48 class VIS_HIDDEN DyldSharedCache
52 #if BUILDING_CACHE_BUILDER
53 enum CodeSigningDigestMode
62 std::string outputFilePath
;
63 std::string outputMapFilePath
;
64 const dyld3::GradedArchs
* archs
;
65 dyld3::Platform platform
;
66 bool excludeLocalSymbols
;
69 CodeSigningDigestMode codeSigningDigestMode
;
70 bool dylibsRemovedDuringMastering
;
71 bool inodesAreSameAsRuntime
;
72 bool cacheSupportsASLR
;
74 bool isLocallyBuiltCache
;
76 bool evictLeafDylibsOnOverflow
;
77 std::unordered_map
<std::string
, unsigned> dylibOrdering
;
78 std::unordered_map
<std::string
, unsigned> dirtyDataSegmentOrdering
;
79 std::string loggingPrefix
;
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
) { }
89 std::string runtimePath
;
90 const dyld3::MachOAnalyzer
* mh
;
92 uint64_t isSetUID
: 1,
95 uint64_t modTime
; // only recorded if inodesAreSameAsRuntime
96 uint64_t inode
; // only recorded if inodesAreSameAsRuntime
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
;
112 std::string realPath
;
113 std::string aliasPath
;
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
);
125 // This function is single threaded and creates a shared cache. The cache file is created in-memory.
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
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
141 // cacheContent: nullptr
142 // errorMessage: the string describing why the cache could not be created
143 // warnings: all warning messsages generated before the failure
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
);
153 // Returns a text "map" file as a big string
155 std::string
mapFile() const;
157 #endif // TARGET_OS_OSX
161 // Returns the architecture name of the shared cache, e.g. "arm64"
163 const char* archName() const;
167 // Returns the platform the cache is for
169 dyld3::Platform
platform() const;
173 // Iterates over each dylib in the cache
175 void forEachImage(void (^handler
)(const mach_header
* mh
, const char* installName
)) const;
179 // Searches cache for dylib with specified path
181 bool hasImagePath(const char* dylibPath
, uint32_t& imageIndex
) const;
185 // Path is to a dylib in the cache and this is an optimized cache so that path cannot be overridden
187 bool hasNonOverridablePath(const char* dylibPath
) const;
191 // Searches cache for dylib with specified mach_header
193 bool findMachHeaderImageIndex(const mach_header
* mh
, uint32_t& imageIndex
) const;
196 // Iterates over each dylib in the cache
198 void forEachImageEntry(void (^handler
)(const char* path
, uint64_t mTime
, uint64_t inode
)) const;
202 // Iterates over each dylib in the cache
204 const mach_header
* getIndexedImageEntry(uint32_t index
, uint64_t& mTime
, uint64_t& node
) const;
208 // Iterates over each dylib in the cache
210 void forEachImageTextSegment(void (^handler
)(uint64_t loadAddressUnslid
, uint64_t textSegmentSize
, const uuid_t dylibUUID
, const char* installName
, bool& stop
)) const;
214 // Iterates over each of the three regions in the cache
216 void forEachRegion(void (^handler
)(const void* content
, uint64_t vmAddr
, uint64_t size
, uint32_t permissions
)) const;
220 // Returns if an address range is in this cache, and if so if in a read-only area
222 bool inCache(const void* addr
, size_t length
, bool& readOnly
) const;
226 // returns address the cache would load at if unslid
228 uint64_t unslidLoadAddress() const;
232 // returns UUID of cache
234 void getUUID(uuid_t uuid
) const;
238 // returns the vm size required to map cache
240 uint64_t mappedSize() const;
244 // searches cache for pre-built closure for program
246 const dyld3::closure::LaunchClosure
* findClosure(const char* executablePath
) const;
250 // iterates all pre-built closures for program
252 void forEachLaunchClosure(void (^handler
)(const char* executableRuntimePath
, const dyld3::closure::LaunchClosure
* closure
)) const;
256 // iterates all pre-built Image* for OS dylibs/bundles not in dyld cache
258 void forEachDlopenImage(void (^handler
)(const char* runtimePath
, const dyld3::closure::Image
* image
)) const;
262 // returns the ImageArray pointer to Images in dyld shared cache
264 const dyld3::closure::ImageArray
* cachedDylibsImageArray() const;
268 // returns the ImageArray pointer to Images in OS with pre-build dlopen closure
270 const dyld3::closure::ImageArray
* otherOSImageArray() const;
274 // searches cache for pre-built dlopen closure for OS dylib/bundle
276 const dyld3::closure::Image
* findDlopenOtherImage(const char* path
) const;
279 // Returns the pointer to the slide info for this cache
281 const dyld_cache_slide_info
* slideInfo() const;
284 // Returns a pointer to the start of the __DATA region in the cache
286 const uint8_t* dataRegionStart() const;
289 // Returns a pointer to the shared cache optimized Objective-C data structures
291 const objc_opt::objc_opt_t
* objcOpt() const;
294 // Returns a pointer to the shared cache optimized Objective-C pointer structures
296 const void* objcOptPtrs() const;
300 // returns true if the offset is in the TEXT of some cached dylib and sets *index to the dylib index
302 bool addressInText(uint32_t cacheOffset
, uint32_t* index
) const;
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;
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
;
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();
325 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
326 // MRM map file generator
327 std::string
generateJSONMap(const char* disposition
) const;
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;
339 dyld_cache_header header
;
342 // Returns a variable of type "const T" which corresponds to the header field with the given unslid address
344 const T
getAddrField(uint64_t addr
) const;
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;
362 #endif /* DyldSharedCache_h */