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"
49 class VIS_HIDDEN DyldSharedCache
53 #if BUILDING_CACHE_BUILDER
54 enum CodeSigningDigestMode
61 enum class LocalSymbolsMode
{
69 std::string outputFilePath
;
70 std::string outputMapFilePath
;
71 const dyld3::GradedArchs
* archs
;
72 dyld3::Platform platform
;
73 LocalSymbolsMode localSymbolMode
;
75 bool optimizeDyldDlopens
;
76 bool optimizeDyldLaunches
;
77 CodeSigningDigestMode codeSigningDigestMode
;
78 bool dylibsRemovedDuringMastering
;
79 bool inodesAreSameAsRuntime
;
80 bool cacheSupportsASLR
;
82 bool isLocallyBuiltCache
;
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
;
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
) { }
98 std::string runtimePath
;
99 const dyld3::MachOAnalyzer
* mh
;
101 uint64_t isSetUID
: 1,
103 sliceFileOffset
: 62;
104 uint64_t modTime
; // only recorded if inodesAreSameAsRuntime
105 uint64_t inode
; // only recorded if inodesAreSameAsRuntime
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
;
121 std::string realPath
;
122 std::string aliasPath
;
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
);
134 // This function is single threaded and creates a shared cache. The cache file is created in-memory.
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
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
150 // cacheContent: nullptr
151 // errorMessage: the string describing why the cache could not be created
152 // warnings: all warning messsages generated before the failure
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
);
162 // Returns a text "map" file as a big string
164 std::string
mapFile() const;
166 #endif // BUILDING_CACHE_BUILDER
170 // Returns the architecture name of the shared cache, e.g. "arm64"
172 const char* archName() const;
176 // Returns the platform the cache is for
178 dyld3::Platform
platform() const;
182 // Iterates over each dylib in the cache
184 void forEachImage(void (^handler
)(const mach_header
* mh
, const char* installName
)) const;
188 // Searches cache for dylib with specified path
190 bool hasImagePath(const char* dylibPath
, uint32_t& imageIndex
) const;
194 // Is this path (which we know is in the shared cache), overridable
196 bool isOverridablePath(const char* dylibPath
) const;
200 // Path is to a dylib in the cache and this is an optimized cache so that path cannot be overridden
202 bool hasNonOverridablePath(const char* dylibPath
) const;
206 // Check if shared cache contains local symbols info
208 const bool hasLocalSymbolsInfo() const;
212 // Get code signature mapped address
214 uint64_t getCodeSignAddress() const;
218 // Searches cache for dylib with specified mach_header
220 bool findMachHeaderImageIndex(const mach_header
* mh
, uint32_t& imageIndex
) const;
223 // Iterates over each dylib in the cache
225 void forEachImageEntry(void (^handler
)(const char* path
, uint64_t mTime
, uint64_t inode
)) const;
229 // Get image entry from index
231 const mach_header
* getIndexedImageEntry(uint32_t index
, uint64_t& mTime
, uint64_t& node
) const;
234 // iterates over all dylibs and aliases
235 void forEachDylibPath(void (^handler
)(const char* dylibPath
, uint32_t index
)) const;
239 // Get image path from index
241 const char* getIndexedImagePath(uint32_t index
) const;
245 // Get the canonical (dylib) path for a given path, which may be a symlink to something in the cache
247 const char* getCanonicalPath(const char* path
) const;
251 // Iterates over each text segment in the cache
253 void forEachImageTextSegment(void (^handler
)(uint64_t loadAddressUnslid
, uint64_t textSegmentSize
, const uuid_t dylibUUID
, const char* installName
, bool& stop
)) const;
257 // Iterates over each of the three regions in the cache
259 void forEachRegion(void (^handler
)(const void* content
, uint64_t vmAddr
, uint64_t size
, uint32_t permissions
,
260 uint64_t flags
)) const;
264 // Get local symbols nlist entries
266 const void* getLocalNlistEntries() const;
270 // Get local symbols nlist count
272 const uint32_t getLocalNlistCount() const;
276 // Get local symbols strings
278 const char* getLocalStrings() const;
282 // Get local symbols strings size
284 const uint32_t getLocalStringsSize() const;
288 // Iterates over each local symbol entry in the cache
290 void forEachLocalSymbolEntry(void (^handler
)(uint32_t dylibOffset
, uint32_t nlistStartIndex
, uint32_t nlistCount
, bool& stop
)) const;
293 // Returns if an address range is in this cache, and if so if in a read-only area
295 bool inCache(const void* addr
, size_t length
, bool& readOnly
) const;
298 // Returns true if a path is an alternate path (symlink)
300 bool isAlias(const char* path
) const;
303 // returns address the cache would load at if unslid
305 uint64_t unslidLoadAddress() const;
309 // returns UUID of cache
311 void getUUID(uuid_t uuid
) const;
315 // returns the vm size required to map cache
317 uint64_t mappedSize() const;
321 // searches cache for pre-built closure for program
323 const dyld3::closure::LaunchClosure
* findClosure(const char* executablePath
) const;
327 // iterates all pre-built closures for program
329 void forEachLaunchClosure(void (^handler
)(const char* executableRuntimePath
, const dyld3::closure::LaunchClosure
* closure
)) const;
333 // iterates all pre-built Image* for OS dylibs/bundles not in dyld cache
335 void forEachDlopenImage(void (^handler
)(const char* runtimePath
, const dyld3::closure::Image
* image
)) const;
339 // returns the ImageArray pointer to Images in dyld shared cache
341 const dyld3::closure::ImageArray
* cachedDylibsImageArray() const;
345 // returns the ImageArray pointer to Images in OS with pre-build dlopen closure
347 const dyld3::closure::ImageArray
* otherOSImageArray() const;
351 // searches cache for pre-built dlopen closure for OS dylib/bundle
353 const dyld3::closure::Image
* findDlopenOtherImage(const char* path
) const;
356 // Returns the pointer to the slide info for this cache
358 const dyld_cache_slide_info
* legacyCacheSlideInfo() const;
361 // Returns a pointer to the __DATA region mapping in the cache
363 const dyld_cache_mapping_info
* legacyCacheDataRegionMapping() const;
366 // Returns a pointer to the start of the __DATA region in the cache
368 const uint8_t* legacyCacheDataRegionBuffer() const;
371 // Returns a pointer to the shared cache optimized Objective-C data structures
373 const objc_opt::objc_opt_t
* objcOpt() const;
376 // Returns a pointer to the shared cache optimized Objective-C pointer structures
378 const void* objcOptPtrs() const;
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;
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;
391 // returns true if the offset is in the TEXT of some cached dylib and sets *index to the dylib index
393 bool addressInText(uint32_t cacheOffset
, uint32_t* index
) const;
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;
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
;
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();
416 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
417 // MRM map file generator
418 std::string
generateJSONMap(const char* disposition
) const;
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;
430 // Note these enum entries are only valid for 64-bit archs.
431 enum class ConstantClasses
{
432 cfStringAtomSize
= 32
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;
439 #if !(BUILDING_LIBDYLD || BUILDING_DYLD)
440 dyld3::MachOAnalyzer::VMAddrConverter
makeVMAddrConverter(bool contentRebased
) const;
443 dyld_cache_header header
;
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;
451 // Returns a variable of type "const T" which corresponds to the header field with the given unslid address
453 const T
getAddrField(uint64_t addr
) const;
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;
471 #endif /* DyldSharedCache_h */