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();
107 void disableInterposing() { _interposingDisabled
= true; }
110 struct PatchableExport
112 uint32_t cacheOffsetOfImpl
;
113 uint32_t cacheOffsetOfName
;
114 uint32_t patchLocationsCount
;
115 const dyld_cache_patchable_location
* patchLocations
;
118 struct CachedDylibInfo
120 LoadedFileInfo fileInfo
;
123 struct CachedDylibAlias
125 const char* realPath
;
126 const char* aliasPath
;
129 const ImageArray
* makeDyldCacheImageArray(bool customerCache
, const Array
<CachedDylibInfo
>& dylibs
, const Array
<CachedDylibAlias
>& aliases
);
131 const ImageArray
* makeOtherDylibsImageArray(const Array
<LoadedFileInfo
>& otherDylibs
, uint32_t cachedDylibsCount
);
133 static void buildLoadOrder(Array
<LoadedImage
>& loadedList
, const Array
<const ImageArray
*>& imagesArrays
, const Closure
* toAdd
);
145 struct BuilderLoadedImage
147 Array
<Image
::LinkedImage
> dependents
;
149 uint32_t unmapWhenDone
: 1,
155 mustBuildClosure
: 1,
156 hasMissingWeakImports
: 1,
158 overrideImageNum
: 12;
159 LoadedFileInfo loadedFileInfo
;
161 // Convenience method to get the information from the loadedFileInfo
162 const MachOAnalyzer
* loadAddress() const { return (const MachOAnalyzer
*)loadedFileInfo
.fileContent
; }
163 const char* path() const { return loadedFileInfo
.path
; }
166 struct LoadedImageChain
168 LoadedImageChain
* previous
;
169 BuilderLoadedImage
& image
;
172 // Represents how the current image is linked
173 enum class LinkageType
{
174 kStatic
, // Linked via LC_LOAD_* by main executable or other dylib
175 kDynamic
, // Only used for the image we dlopen'ed, not anything it links
176 kInserted
// This is an inserted library
179 typedef LaunchClosure
::SkippedFile SkippedFile
;
182 void recursiveLoadDependents(LoadedImageChain
& forImageChain
, bool canUseSharedCacheClosure
= true);
183 void loadDanglingUpwardLinks(bool canUseSharedCacheClosure
= true);
184 void forEachResolvedPathVar(const char* loadPath
, const LoadedImageChain
& forImageChain
, bool implictRPath
, LinkageType linkageType
,
185 void (^handler
)(const char* possiblePath
, bool& stop
));
186 bool findImage(const char* loadPath
, const LoadedImageChain
& forImageChain
, BuilderLoadedImage
*& foundImage
, LinkageType linkageType
,
187 uint32_t compatVersion
, bool canUseSharedCacheClosure
);
188 void buildImage(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
189 void addSegments(ImageWriter
& writer
, const MachOAnalyzer
* mh
);
190 void addRebaseInfo(ImageWriter
& writer
, const MachOAnalyzer
* mh
);
191 void addSynthesizedRebaseInfo(ImageWriter
& writer
, const MachOAnalyzer
* mh
);
192 void addSynthesizedBindInfo(ImageWriter
& writer
, const MachOAnalyzer
* mh
);
193 void addBindInfo(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
194 void reportRebasesAndBinds(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
195 void addChainedFixupInfo(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
196 void addInterposingTuples(LaunchClosureWriter
& writer
, const Image
* image
, const MachOAnalyzer
* mh
);
197 void computeInitOrder(ImageWriter
& writer
, uint32_t loadIndex
);
198 void addClosureInfo(LaunchClosureWriter
& closureWriter
);
199 void depthFirstRecurseSetInitInfo(uint32_t loadIndex
, InitInfo initInfos
[], uint32_t& initOrder
, bool& hasError
);
200 bool findSymbol(BuilderLoadedImage
& fromImage
, int libraryOrdinal
, const char* symbolName
, bool weakImport
, bool lazyBind
, uint64_t addend
,
201 Image
::ResolvedSymbolTarget
& target
, ResolvedTargetInfo
& targetInfo
);
202 bool findSymbolInImage(const MachOAnalyzer
* macho
, const char* symbolName
, uint64_t addend
, bool followReExports
,
203 bool weakImport
, Image
::ResolvedSymbolTarget
& target
, ResolvedTargetInfo
& targetInfo
);
204 const MachOAnalyzer
* machOForImageNum(ImageNum imageNum
);
205 ImageNum
imageNumForMachO(const MachOAnalyzer
* mh
);
206 const MachOAnalyzer
* findDependent(const MachOLoaded
* mh
, uint32_t depIndex
);
207 BuilderLoadedImage
& findLoadedImage(ImageNum imageNum
);
208 BuilderLoadedImage
& findLoadedImage(const MachOAnalyzer
* mh
);
209 uint32_t index(const BuilderLoadedImage
&);
210 bool expandAtLoaderPath(const char* loadPath
, bool fromLCRPATH
, const BuilderLoadedImage
& loadedImage
, char fixedPath
[]);
211 bool expandAtExecutablePath(const char* loadPath
, bool fromLCRPATH
, char fixedPath
[]);
212 void addMustBeMissingPath(const char* path
);
213 void addSkippedFile(const char* path
, uint64_t inode
, uint64_t mtime
);
214 const char* strdup_temp(const char* path
);
215 bool overridableDylib(const BuilderLoadedImage
& forImage
);
216 void forEachBind(BuilderLoadedImage
& forImage
, void (^handler
)(uint64_t runtimeOffset
, Image
::ResolvedSymbolTarget target
, const ResolvedTargetInfo
& targetInfo
, bool& stop
),
217 void (^strongHandler
)(const char* strongSymbolName
),
218 void (^missingLazyBindHandler
)());
219 bool findMissingSymbolHandler(Image
::ResolvedSymbolTarget
& target
, ResolvedTargetInfo
& targetInfo
);
222 static size_t hash(const char* v
);
225 struct EqualCString
{
226 static bool equal(const char* s1
, const char* s2
);
231 static size_t hash(const T
* v
) {
232 return std
::hash
<const T
*>{}(v
);
236 struct EqualPointer
{
238 static bool equal(const T
* s1
, const T
* s2
) {
243 struct ObjCOptimizerImage
{
245 ObjCOptimizerImage() {
248 ~ObjCOptimizerImage() {
251 typedef std
::pair
<closure
::Image
::ObjCClassNameImageOffset
, closure
::Image
::ObjCClassImageOffset
> SeenClass
;
253 struct SelectorFixup
{
254 uint32_t fixupVMOffset
;
258 uint32_t selectorTableIndex
;
261 const char* selectorString
;
266 BuilderLoadedImage
* loadedImage
= nullptr;
267 ImageWriter
* writer
= nullptr;
268 uint64_t fairplayFileOffsetStart
= 0;
269 uint64_t fairplayFileOffsetEnd
= 0;
272 // Image info optimisation
273 uint64_t objcImageInfoVMOffset
;
275 // Class and protocol optimisation data structures
276 OverflowSafeArray
<std
::pair
<uint64_t, uint64_t>> classesNameAndDataVMOffsets
;
277 OverflowSafeArray
<SeenClass
> seenClasses
;
278 OverflowSafeArray
<uint64_t> classStableSwiftFixups
;
279 Map
<const char*, dyld3
::closure
::Image
::ObjCDuplicateClass
, HashCString
, EqualCString
> classSharedCacheDuplicates
;
280 OverflowSafeArray
<SeenClass
> seenProtocols
;
281 OverflowSafeArray
<uint64_t> protocolISAFixups
;
283 // Selector optimsation data structures
284 OverflowSafeArray
<SelectorFixup
> selectorFixups
;
285 Map
<const char*, dyld3
::closure
::Image
::ObjCImageOffset
, HashCString
, EqualCString
> selectorMap
;
286 std
::optional
<uint64_t> methodNameVMOffset
;
289 bool optimizeObjC(Array
<ImageWriter
>& writers
);
290 void optimizeObjCSelectors(const objc_opt
::objc_selopt_t
* objcSelOpt
,
291 const Map
<const char*, dyld3
::closure
::Image
::ObjCImageOffset
, HashCString
, EqualCString
>& closureSelectorMap
,
292 ObjCOptimizerImage
& image
);
293 void optimizeObjCClasses(const objc_opt
::objc_clsopt_t
* objcClassOpt
,
294 const Map
<const dyld3
::MachOAnalyzer
*, bool, HashPointer
, EqualPointer
>& sharedCacheImagesMap
,
295 const Map
<const char*, dyld3
::closure
::Image
::ObjCDuplicateClass
, HashCString
, EqualCString
>& duplicateSharedCacheClasses
,
296 ObjCOptimizerImage
& image
);
297 void optimizeObjCProtocols(const objc_opt
::objc_protocolopt2_t
* objcProtocolOpt
,
298 const Map
<const dyld3
::MachOAnalyzer
*, bool, HashPointer
, EqualPointer
>& sharedCacheImagesMap
,
299 ObjCOptimizerImage
& image
);
300 void writeClassOrProtocolHashTable(bool classes
, Array
<ObjCOptimizerImage
>& objcImages
);
302 void addDuplicateObjCClassWarning(const char* className
,
303 const char* duplicateDefinitionPath
,
304 const char* canonicalDefinitionPath
);
306 static bool inLoadedImageArray(const Array
<LoadedImage
>& loadedList
, ImageNum imageNum
);
307 static void buildLoadOrderRecurse(Array
<LoadedImage
>& loadedList
, const Array
<const ImageArray
*>& imagesArrays
, const Image
* toAdd
);
308 void invalidateInitializerRoots();
310 const FileSystem
& _fileSystem
;
311 const DyldSharedCache
* const _dyldCache
;
312 const PathOverrides
& _pathOverrides
;
313 const GradedArchs
& _archs
;
314 Platform
const _platform
;
315 uint32_t const _startImageNum
;
316 const ImageArray
* _dyldImageArray
= nullptr;
317 const CacheDylibsBindingHandlers
* _handlers
= nullptr;
318 const Array
<CachedDylibAlias
>* _aliases
= nullptr;
319 const AtPath _atPathHandling
= AtPath
::none
;
320 uint32_t _mainProgLoadIndex
= 0;
321 const char* _mainProgLoadPath
= nullptr;
323 LaunchErrorInfo
* _launchErrorInfo
= nullptr;
324 PathPool
* _tempPaths
= nullptr;
325 PathPool
* _mustBeMissingPaths
= nullptr;
326 OverflowSafeArray
<SkippedFile
> _skippedFiles
;
327 uint32_t _nextIndex
= 0;
328 OverflowSafeArray
<BuilderLoadedImage
,2048> _loadedImages
;
329 OverflowSafeArray
<Image
::LinkedImage
,65536> _dependencies
; // all dylibs in cache need ~20,000 edges
330 OverflowSafeArray
<InterposingTuple
> _interposingTuples
;
331 OverflowSafeArray
<Closure
::PatchEntry
> _weakDefCacheOverrides
;
332 OverflowSafeArray
<const char*> _weakDefsFromChainedBinds
;
333 OverflowSafeArray
<uint8_t> _objcSelectorsHashTable
;
334 OverflowSafeArray
<Image
::ObjCSelectorImage
> _objcSelectorsHashTableImages
;
335 OverflowSafeArray
<uint8_t> _objcClassesHashTable
;
336 OverflowSafeArray
<uint8_t> _objcProtocolsHashTable
;
337 OverflowSafeArray
<Image
::ObjCClassImage
> _objcClassesHashTableImages
;
338 OverflowSafeArray
<uint8_t> _objcClassesDuplicatesHashTable
;
339 PathPool
* _objcDuplicateClassWarnings
= nullptr;
340 uint32_t _alreadyInitedIndex
= 0;
341 bool _isLaunchClosure
= false;
342 bool _makingDyldCacheImages
= false;
343 bool _dyldCacheIsLive
= false; // means kernel is rebasing dyld cache content being viewed
344 bool _makingClosuresInCache
= false;
345 bool _makingCustomerCache
= false;
346 bool _allowRelativePaths
= false;
347 bool _atPathUsed
= false;
348 bool _interposingTuplesUsed
= false;
349 bool _fallbackPathUsed
= false;
350 bool _allowMissingLazies
= false;
351 bool _dyldCacheInvalidFormatVersion
= false;
352 bool _foundNonCachedImage
= false; // true means we have one or more images from disk we need to build closure(s) for
353 bool _foundDyldCacheRoots
= false; // true if one or more images are roots of the shared cache
354 bool _foundMissingLazyBinds
= false; // true if one or more images having missing lazy binds
355 bool _interposingDisabled
= false;
356 ImageNum _libDyldImageNum
= 0;
357 ImageNum _libSystemImageNum
= 0;
364 } // namespace closure
368 #endif /* ClosureBuilder_h */