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 ClosureBuilder_h
26 #define ClosureBuilder_h
30 #include "ClosureFileSystem.h"
31 #include "ClosureWriter.h"
32 #include "PathOverrides.h"
33 #include "DyldSharedCache.h"
34 #include "MachOAnalyzer.h"
43 struct objc_protocolopt2_t
;
53 class VIS_HIDDEN ClosureBuilder
57 struct LaunchErrorInfo
60 const char* clientOfDylibPath
;
61 const char* targetDylibPath
;
65 struct ResolvedTargetInfo
67 const MachOLoaded
* foundInDylib
;
68 const char* requestedSymbolName
;
69 const char* foundSymbolName
;
72 bool weakBindSameImage
;
74 bool skippableWeakDef
;
78 struct CacheDylibsBindingHandlers
80 void (^rebase
)(ImageNum
, const MachOLoaded
* imageToFix
, uint32_t runtimeOffset
);
81 void (^bind
)(ImageNum
, const MachOLoaded
* imageToFix
, uint32_t runtimeOffset
, Image
::ResolvedSymbolTarget target
, const ResolvedTargetInfo
& targetInfo
);
82 void (^chainedBind
)(ImageNum
, const MachOLoaded
*, const dyld_chained_starts_in_image
* starts
, const Array
<Image
::ResolvedSymbolTarget
>& targets
, const Array
<ResolvedTargetInfo
>& targetInfos
);
85 enum class AtPath
{ none
, all
, onlyInRPaths
};
87 ClosureBuilder(uint32_t startImageNum
, const FileSystem
& fileSystem
, const DyldSharedCache
* dyldCache
, bool dyldCacheIsLive
,
88 const GradedArchs
& archs
, const PathOverrides
& pathOverrides
,
89 AtPath atPathHandling
=AtPath
::all
, bool allowRelativePaths
=true, LaunchErrorInfo
* errorInfo
=nullptr,
90 Platform platform
=MachOFile
::currentPlatform(), const CacheDylibsBindingHandlers
* handlers
=nullptr);
92 Diagnostics
& diagnostics() { return _diag
; }
94 const LaunchClosure
* makeLaunchClosure(const LoadedFileInfo
& fileInfo
, bool allowInsertFailures
);
96 const LaunchClosure
* makeLaunchClosure(const char* mainPath
,bool allowInsertFailures
);
99 static const DlopenClosure
* sRetryDlopenClosure
;
100 const DlopenClosure
* makeDlopenClosure(const char* dylibPath
, const LaunchClosure
* mainClosure
, const Array
<LoadedImage
>& loadedList
,
101 closure
::ImageNum callerImageNum
, bool noLoad
, bool forceBindLazies
, bool canUseSharedCacheClosure
,
102 closure
::ImageNum
* topImageNum
);
104 ImageNum
nextFreeImageNum() const { return _startImageNum
+ _nextIndex
; }
106 void setDyldCacheInvalidFormatVersion();
109 struct PatchableExport
111 uint32_t cacheOffsetOfImpl
;
112 uint32_t cacheOffsetOfName
;
113 uint32_t patchLocationsCount
;
114 const dyld_cache_patchable_location
* patchLocations
;
117 struct CachedDylibInfo
119 LoadedFileInfo fileInfo
;
122 struct CachedDylibAlias
124 const char* realPath
;
125 const char* aliasPath
;
128 const ImageArray
* makeDyldCacheImageArray(bool customerCache
, const Array
<CachedDylibInfo
>& dylibs
, const Array
<CachedDylibAlias
>& aliases
);
130 const ImageArray
* makeOtherDylibsImageArray(const Array
<LoadedFileInfo
>& otherDylibs
, uint32_t cachedDylibsCount
);
132 static void buildLoadOrder(Array
<LoadedImage
>& loadedList
, const Array
<const ImageArray
*>& imagesArrays
, const Closure
* toAdd
);
144 struct BuilderLoadedImage
146 Array
<Image
::LinkedImage
> dependents
;
148 uint32_t unmapWhenDone
: 1,
154 mustBuildClosure
: 1,
155 hasMissingWeakImports
: 1,
157 overrideImageNum
: 12;
158 LoadedFileInfo loadedFileInfo
;
160 // Convenience method to get the information from the loadedFileInfo
161 const MachOAnalyzer
* loadAddress() const { return (const MachOAnalyzer
*)loadedFileInfo
.fileContent
; }
162 const char* path() const { return loadedFileInfo
.path
; }
165 struct LoadedImageChain
167 LoadedImageChain
* previous
;
168 BuilderLoadedImage
& image
;
171 // Represents how the current image is linked
172 enum class LinkageType
{
173 kStatic
, // Linked via LC_LOAD_* by main executable or other dylib
174 kDynamic
, // Only used for the image we dlopen'ed, not anything it links
175 kInserted
// This is an inserted library
178 typedef LaunchClosure
::SkippedFile SkippedFile
;
181 void recursiveLoadDependents(LoadedImageChain
& forImageChain
, bool canUseSharedCacheClosure
= true);
182 void loadDanglingUpwardLinks(bool canUseSharedCacheClosure
= true);
183 void forEachResolvedPathVar(const char* loadPath
, const LoadedImageChain
& forImageChain
, bool implictRPath
, LinkageType linkageType
,
184 void (^handler
)(const char* possiblePath
, bool& stop
));
185 bool findImage(const char* loadPath
, const LoadedImageChain
& forImageChain
, BuilderLoadedImage
*& foundImage
, LinkageType linkageType
,
186 uint32_t compatVersion
, bool canUseSharedCacheClosure
);
187 void buildImage(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
188 void addSegments(ImageWriter
& writer
, const MachOAnalyzer
* mh
);
189 void addRebaseInfo(ImageWriter
& writer
, const MachOAnalyzer
* mh
);
190 void addSynthesizedRebaseInfo(ImageWriter
& writer
, const MachOAnalyzer
* mh
);
191 void addSynthesizedBindInfo(ImageWriter
& writer
, const MachOAnalyzer
* mh
);
192 void addBindInfo(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
193 void reportRebasesAndBinds(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
194 void addChainedFixupInfo(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
195 void addInterposingTuples(LaunchClosureWriter
& writer
, const Image
* image
, const MachOAnalyzer
* mh
);
196 void computeInitOrder(ImageWriter
& writer
, uint32_t loadIndex
);
197 void addClosureInfo(LaunchClosureWriter
& closureWriter
);
198 void depthFirstRecurseSetInitInfo(uint32_t loadIndex
, InitInfo initInfos
[], uint32_t& initOrder
, bool& hasError
);
199 bool findSymbol(BuilderLoadedImage
& fromImage
, int libraryOrdinal
, const char* symbolName
, bool weakImport
, bool lazyBind
, uint64_t addend
,
200 Image
::ResolvedSymbolTarget
& target
, ResolvedTargetInfo
& targetInfo
);
201 bool findSymbolInImage(const MachOAnalyzer
* macho
, const char* symbolName
, uint64_t addend
, bool followReExports
,
202 bool weakImport
, Image
::ResolvedSymbolTarget
& target
, ResolvedTargetInfo
& targetInfo
);
203 const MachOAnalyzer
* machOForImageNum(ImageNum imageNum
);
204 ImageNum
imageNumForMachO(const MachOAnalyzer
* mh
);
205 const MachOAnalyzer
* findDependent(const MachOLoaded
* mh
, uint32_t depIndex
);
206 BuilderLoadedImage
& findLoadedImage(ImageNum imageNum
);
207 BuilderLoadedImage
& findLoadedImage(const MachOAnalyzer
* mh
);
208 uint32_t index(const BuilderLoadedImage
&);
209 bool expandAtLoaderPath(const char* loadPath
, bool fromLCRPATH
, const BuilderLoadedImage
& loadedImage
, char fixedPath
[]);
210 bool expandAtExecutablePath(const char* loadPath
, bool fromLCRPATH
, char fixedPath
[]);
211 void addMustBeMissingPath(const char* path
);
212 void addSkippedFile(const char* path
, uint64_t inode
, uint64_t mtime
);
213 const char* strdup_temp(const char* path
);
214 bool overridableDylib(const BuilderLoadedImage
& forImage
);
215 void forEachBind(BuilderLoadedImage
& forImage
, void (^handler
)(uint64_t runtimeOffset
, Image
::ResolvedSymbolTarget target
, const ResolvedTargetInfo
& targetInfo
, bool& stop
),
216 void (^strongHandler
)(const char* strongSymbolName
),
217 void (^missingLazyBindHandler
)());
218 bool findMissingSymbolHandler(Image
::ResolvedSymbolTarget
& target
, ResolvedTargetInfo
& targetInfo
);
221 static size_t hash(const char* v
);
224 struct EqualCString
{
225 static bool equal(const char* s1
, const char* s2
);
230 static size_t hash(const T
* v
) {
231 return std
::hash
<const T
*>{}(v
);
235 struct EqualPointer
{
237 static bool equal(const T
* s1
, const T
* s2
) {
242 struct ObjCOptimizerImage
{
244 ObjCOptimizerImage() {
247 ~ObjCOptimizerImage() {
250 typedef std
::pair
<closure
::Image
::ObjCClassNameImageOffset
, closure
::Image
::ObjCClassImageOffset
> SeenClass
;
252 struct SelectorFixup
{
253 uint32_t fixupVMOffset
;
257 uint32_t selectorTableIndex
;
260 const char* selectorString
;
265 BuilderLoadedImage
* loadedImage
= nullptr;
266 ImageWriter
* writer
= nullptr;
267 uint64_t fairplayFileOffsetStart
= 0;
268 uint64_t fairplayFileOffsetEnd
= 0;
271 // Image info optimisation
272 uint64_t objcImageInfoVMOffset
;
274 // Class and protocol optimisation data structures
275 OverflowSafeArray
<std
::pair
<uint64_t, uint64_t>> classesNameAndDataVMOffsets
;
276 OverflowSafeArray
<SeenClass
> seenClasses
;
277 OverflowSafeArray
<uint64_t> classStableSwiftFixups
;
278 Map
<const char*, dyld3
::closure
::Image
::ObjCDuplicateClass
, HashCString
, EqualCString
> classSharedCacheDuplicates
;
279 OverflowSafeArray
<SeenClass
> seenProtocols
;
280 OverflowSafeArray
<uint64_t> protocolISAFixups
;
282 // Selector optimsation data structures
283 OverflowSafeArray
<SelectorFixup
> selectorFixups
;
284 Map
<const char*, dyld3
::closure
::Image
::ObjCImageOffset
, HashCString
, EqualCString
> selectorMap
;
285 std
::optional
<uint64_t> methodNameVMOffset
;
288 bool optimizeObjC(Array
<ImageWriter
>& writers
);
289 void optimizeObjCSelectors(const objc_opt
::objc_selopt_t
* objcSelOpt
,
290 const Map
<const char*, dyld3
::closure
::Image
::ObjCImageOffset
, HashCString
, EqualCString
>& closureSelectorMap
,
291 ObjCOptimizerImage
& image
);
292 void optimizeObjCClasses(const objc_opt
::objc_clsopt_t
* objcClassOpt
,
293 const Map
<const dyld3
::MachOAnalyzer
*, bool, HashPointer
, EqualPointer
>& sharedCacheImagesMap
,
294 const Map
<const char*, dyld3
::closure
::Image
::ObjCDuplicateClass
, HashCString
, EqualCString
>& duplicateSharedCacheClasses
,
295 ObjCOptimizerImage
& image
);
296 void optimizeObjCProtocols(const objc_opt
::objc_protocolopt2_t
* objcProtocolOpt
,
297 const Map
<const dyld3
::MachOAnalyzer
*, bool, HashPointer
, EqualPointer
>& sharedCacheImagesMap
,
298 ObjCOptimizerImage
& image
);
299 void writeClassOrProtocolHashTable(bool classes
, Array
<ObjCOptimizerImage
>& objcImages
);
301 void addDuplicateObjCClassWarning(const char* className
,
302 const char* duplicateDefinitionPath
,
303 const char* canonicalDefinitionPath
);
305 static bool inLoadedImageArray(const Array
<LoadedImage
>& loadedList
, ImageNum imageNum
);
306 static void buildLoadOrderRecurse(Array
<LoadedImage
>& loadedList
, const Array
<const ImageArray
*>& imagesArrays
, const Image
* toAdd
);
307 void invalidateInitializerRoots();
309 const FileSystem
& _fileSystem
;
310 const DyldSharedCache
* const _dyldCache
;
311 const PathOverrides
& _pathOverrides
;
312 const GradedArchs
& _archs
;
313 Platform
const _platform
;
314 uint32_t const _startImageNum
;
315 const ImageArray
* _dyldImageArray
= nullptr;
316 const CacheDylibsBindingHandlers
* _handlers
= nullptr;
317 const Array
<CachedDylibAlias
>* _aliases
= nullptr;
318 const AtPath _atPathHandling
= AtPath
::none
;
319 uint32_t _mainProgLoadIndex
= 0;
320 const char* _mainProgLoadPath
= nullptr;
322 LaunchErrorInfo
* _launchErrorInfo
= nullptr;
323 PathPool
* _tempPaths
= nullptr;
324 PathPool
* _mustBeMissingPaths
= nullptr;
325 OverflowSafeArray
<SkippedFile
> _skippedFiles
;
326 uint32_t _nextIndex
= 0;
327 OverflowSafeArray
<BuilderLoadedImage
,2048> _loadedImages
;
328 OverflowSafeArray
<Image
::LinkedImage
,65536> _dependencies
; // all dylibs in cache need ~20,000 edges
329 OverflowSafeArray
<InterposingTuple
> _interposingTuples
;
330 OverflowSafeArray
<Closure
::PatchEntry
> _weakDefCacheOverrides
;
331 OverflowSafeArray
<const char*> _weakDefsFromChainedBinds
;
332 OverflowSafeArray
<uint8_t> _objcSelectorsHashTable
;
333 OverflowSafeArray
<Image
::ObjCSelectorImage
> _objcSelectorsHashTableImages
;
334 OverflowSafeArray
<uint8_t> _objcClassesHashTable
;
335 OverflowSafeArray
<uint8_t> _objcProtocolsHashTable
;
336 OverflowSafeArray
<Image
::ObjCClassImage
> _objcClassesHashTableImages
;
337 OverflowSafeArray
<uint8_t> _objcClassesDuplicatesHashTable
;
338 PathPool
* _objcDuplicateClassWarnings
= nullptr;
339 uint32_t _alreadyInitedIndex
= 0;
340 bool _isLaunchClosure
= false;
341 bool _makingDyldCacheImages
= false;
342 bool _dyldCacheIsLive
= false; // means kernel is rebasing dyld cache content being viewed
343 bool _makingClosuresInCache
= false;
344 bool _makingCustomerCache
= false;
345 bool _allowRelativePaths
= false;
346 bool _atPathUsed
= false;
347 bool _fallbackPathUsed
= false;
348 bool _allowMissingLazies
= false;
349 bool _dyldCacheInvalidFormatVersion
= false;
350 bool _foundNonCachedImage
= false; // true means we have one or more images from disk we need to build closure(s) for
351 bool _foundDyldCacheRoots
= false; // true if one or more images are roots of the shared cache
352 bool _foundMissingLazyBinds
= false; // true if one or more images having missing lazy binds
353 ImageNum _libDyldImageNum
= 0;
354 ImageNum _libSystemImageNum
= 0;
361 } // namespace closure
365 #endif /* ClosureBuilder_h */