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"
35 #include "MachOAnalyzerSet.h"
44 struct objc_protocolopt2_t
;
47 typedef dyld3
::MachOAnalyzerSet
::WrappedMachO WrappedMachO
;
55 class ClosureAnalyzerSet
;
57 class VIS_HIDDEN ClosureBuilder
: public dyld3
::MachOAnalyzerSet
61 struct ResolvedTargetInfo
63 const MachOLoaded
* foundInDylib
;
64 const char* requestedSymbolName
;
65 const char* foundSymbolName
;
68 bool weakBindSameImage
;
70 bool skippableWeakDef
;
74 typedef void (^DylibFixupHandler
)(const MachOLoaded
* fixupIn
, uint64_t fixupLocRuntimeOffset
, PointerMetaData pmd
, const MachOAnalyzerSet
::FixupTarget
& target
);
76 enum class AtPath
{ none
, all
, onlyInRPaths
};
78 ClosureBuilder(uint32_t startImageNum
, const FileSystem
& fileSystem
, const RootsChecker
& rootsChecker
,
79 const DyldSharedCache
* dyldCache
, bool dyldCacheIsLive
,
80 const GradedArchs
& archs
, const PathOverrides
& pathOverrides
,
81 AtPath atPathHandling
=AtPath
::all
, bool allowRelativePaths
=true, LaunchErrorInfo
* errorInfo
=nullptr,
82 Platform platform
=MachOFile
::currentPlatform(), DylibFixupHandler dylibFixupHandler
=nullptr);
84 Diagnostics
& diagnostics() { return _diag
; }
86 const LaunchClosure
* makeLaunchClosure(const LoadedFileInfo
& fileInfo
, bool allowInsertFailures
);
88 const LaunchClosure
* makeLaunchClosure(const char* mainPath
,bool allowInsertFailures
);
89 void makeMinimalClosures() { _makeMinimalClosure
= true; }
90 void setCanSkipEncodingRebases() { _leaveRebasesAsOpcodes
= true; }
92 static const DlopenClosure
* sRetryDlopenClosure
;
93 const DlopenClosure
* makeDlopenClosure(const char* dylibPath
, const LaunchClosure
* mainClosure
, const Array
<LoadedImage
>& loadedList
,
94 closure
::ImageNum callerImageNum
, bool noLoad
, bool forceBindLazies
, bool canUseSharedCacheClosure
,
95 closure
::ImageNum
* topImageNum
);
97 ImageNum
nextFreeImageNum() const { return _startImageNum
+ _nextIndex
; }
98 Platform
platform() const { return _platform
; }
100 void setDyldCacheInvalidFormatVersion();
101 void disableInterposing() { _interposingDisabled
= true; }
104 struct PatchableExport
106 uint32_t cacheOffsetOfImpl
;
107 uint32_t cacheOffsetOfName
;
108 uint32_t patchLocationsCount
;
109 const dyld_cache_patchable_location
* patchLocations
;
112 struct CachedDylibInfo
114 LoadedFileInfo fileInfo
;
117 struct CachedDylibAlias
119 const char* realPath
;
120 const char* aliasPath
;
123 const ImageArray
* makeDyldCacheImageArray(const Array
<CachedDylibInfo
>& dylibs
, const Array
<CachedDylibAlias
>& aliases
);
125 const ImageArray
* makeOtherDylibsImageArray(const Array
<LoadedFileInfo
>& otherDylibs
, uint32_t cachedDylibsCount
);
127 static void buildLoadOrder(Array
<LoadedImage
>& loadedList
, const Array
<const ImageArray
*>& imagesArrays
, const Closure
* toAdd
);
130 friend ClosureAnalyzerSet
;
134 uint32_t initOrder
: 30,
139 struct BuilderLoadedImage
141 Array
<Image
::LinkedImage
> dependents
;
143 uint32_t unmapWhenDone
: 1,
149 mustBuildClosure
: 1,
150 hasMissingWeakImports
: 1,
151 hasInterposingTuples
: 1,
153 overrideImageNum
: 12;
154 uint32_t exportsTrieOffset
;
155 uint32_t exportsTrieSize
;
156 LoadedFileInfo loadedFileInfo
;
158 // Convenience method to get the information from the loadedFileInfo
159 const MachOAnalyzer
* loadAddress() const { return (const MachOAnalyzer
*)loadedFileInfo
.fileContent
; }
160 const char* path() const { return loadedFileInfo
.path
; }
163 struct LoadedImageChain
165 LoadedImageChain
* previous
;
166 BuilderLoadedImage
& image
;
169 // Represents how the current image is linked
170 enum class LinkageType
{
171 kStatic
, // Linked via LC_LOAD_* by main executable or other dylib
172 kDynamic
, // Only used for the image we dlopen'ed, not anything it links
173 kInserted
// This is an inserted library
176 typedef LaunchClosure
::SkippedFile SkippedFile
;
179 void recursiveLoadDependents(LoadedImageChain
& forImageChain
, bool canUseSharedCacheClosure
= true);
180 void loadDanglingUpwardLinks(bool canUseSharedCacheClosure
= true);
181 void forEachResolvedPathVar(const char* loadPath
, const LoadedImageChain
& forImageChain
, bool implictRPath
, LinkageType linkageType
,
182 void (^handler
)(const char* possiblePath
, bool& stop
));
183 bool findImage(const char* loadPath
, const LoadedImageChain
& forImageChain
, BuilderLoadedImage
*& foundImage
, LinkageType linkageType
,
184 uint32_t compatVersion
, bool canUseSharedCacheClosure
);
185 void buildImage(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
186 void addSegments(ImageWriter
& writer
, const MachOAnalyzer
* mh
);
187 void addFixupInfo(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
188 void addChainedFixupInfo(ImageWriter
& writer
, BuilderLoadedImage
& forImage
);
189 void addInterposingTuples(LaunchClosureWriter
& writer
, const Image
* image
, const MachOAnalyzer
* mh
);
190 void computeInitOrder(ImageWriter
& writer
, uint32_t loadIndex
);
191 void addClosureInfo(LaunchClosureWriter
& closureWriter
);
192 void depthFirstRecurseSetInitInfo(uint32_t loadIndex
, InitInfo initInfos
[], uint32_t& initOrder
, bool& hasError
);
193 const MachOAnalyzer
* machOForImageNum(ImageNum imageNum
);
194 ImageNum
imageNumForMachO(const MachOAnalyzer
* mh
);
195 const MachOAnalyzer
* findDependent(const MachOLoaded
* mh
, uint32_t depIndex
);
196 BuilderLoadedImage
& findLoadedImage(ImageNum imageNum
);
197 const BuilderLoadedImage
& findLoadedImage(ImageNum imageNum
) const;
198 BuilderLoadedImage
& findLoadedImage(const MachOAnalyzer
* mh
);
199 uint32_t index(const BuilderLoadedImage
&);
200 bool expandAtLoaderPath(const char* loadPath
, bool fromLCRPATH
, const BuilderLoadedImage
& loadedImage
, char fixedPath
[]);
201 bool expandAtExecutablePath(const char* loadPath
, bool fromLCRPATH
, bool fromLCRPATHinMain
, char fixedPath
[]);
202 void addMustBeMissingPath(const char* path
);
203 void addSkippedFile(const char* path
, uint64_t inode
, uint64_t mtime
);
204 const char* strdup_temp(const char* path
) const;
205 bool overridableDylib(const BuilderLoadedImage
& forImage
);
206 void addOperatorCachePatches(BuilderLoadedImage
& forImage
);
207 void addWeakDefCachePatch(uint32_t cachedDylibIndex
, uint32_t exportCacheOffset
, const FixupTarget
& patchTarget
);
210 static size_t hash(const char* v
);
213 struct EqualCString
{
214 static bool equal(const char* s1
, const char* s2
);
219 static size_t hash(const T
* v
) {
220 return std
::hash
<const T
*>{}(v
);
224 struct EqualPointer
{
226 static bool equal(const T
* s1
, const T
* s2
) {
231 struct ObjCOptimizerImage
{
233 ObjCOptimizerImage() {
236 ~ObjCOptimizerImage() {
239 typedef std
::pair
<closure
::Image
::ObjCClassNameImageOffset
, closure
::Image
::ObjCClassImageOffset
> SeenClass
;
241 struct SelectorFixup
{
242 uint32_t fixupVMOffset
;
246 uint32_t selectorTableIndex
;
249 const char* selectorString
;
254 BuilderLoadedImage
* loadedImage
= nullptr;
255 ImageWriter
* writer
= nullptr;
256 uint64_t fairplayFileOffsetStart
= 0;
257 uint64_t fairplayFileOffsetEnd
= 0;
260 // Image info optimisation
261 uint64_t objcImageInfoVMOffset
;
263 // Class and protocol optimisation data structures
264 OverflowSafeArray
<std
::pair
<uint64_t, uint64_t>> classesNameAndDataVMOffsets
;
265 OverflowSafeArray
<SeenClass
> seenClasses
;
266 OverflowSafeArray
<uint64_t> classStableSwiftFixups
;
267 Map
<const char*, dyld3
::closure
::Image
::ObjCDuplicateClass
, HashCString
, EqualCString
> classSharedCacheDuplicates
;
268 OverflowSafeArray
<SeenClass
> seenProtocols
;
269 OverflowSafeArray
<uint64_t> protocolISAFixups
;
271 // Selector optimsation data structures
272 OverflowSafeArray
<SelectorFixup
> selectorFixups
;
273 Map
<const char*, dyld3
::closure
::Image
::ObjCImageOffset
, HashCString
, EqualCString
> selectorMap
;
274 std
::optional
<uint64_t> methodNameVMOffset
;
275 OverflowSafeArray
<uint64_t> methodListFixups
;
278 bool optimizeObjC(Array
<ImageWriter
>& writers
);
279 void optimizeObjCSelectors(const objc_opt
::objc_selopt_t
* objcSelOpt
,
280 const Map
<const char*, dyld3
::closure
::Image
::ObjCImageOffset
, HashCString
, EqualCString
>& closureSelectorMap
,
281 ObjCOptimizerImage
& image
);
282 void optimizeObjCClasses(const objc_opt
::objc_clsopt_t
* objcClassOpt
,
283 const Map
<const dyld3
::MachOAnalyzer
*, bool, HashPointer
, EqualPointer
>& sharedCacheImagesMap
,
284 const Map
<const char*, dyld3
::closure
::Image
::ObjCDuplicateClass
, HashCString
, EqualCString
>& duplicateSharedCacheClasses
,
285 const Map
<const char*, bool, HashCString
, EqualCString
>& duplicateClassesToIgnore
,
286 ObjCOptimizerImage
& image
);
287 void optimizeObjCProtocols(const objc_opt
::objc_protocolopt2_t
* objcProtocolOpt
,
288 const Map
<const dyld3
::MachOAnalyzer
*, bool, HashPointer
, EqualPointer
>& sharedCacheImagesMap
,
289 ObjCOptimizerImage
& image
);
290 void writeClassOrProtocolHashTable(bool classes
, Array
<ObjCOptimizerImage
>& objcImages
);
292 void addDuplicateObjCClassWarning(const char* className
,
293 const char* duplicateDefinitionPath
,
294 const char* canonicalDefinitionPath
);
296 void parseObjCClassDuplicates(Map
<const char*, bool, HashCString
, EqualCString
>& duplicateClassesToIgnore
);
298 static bool inLoadedImageArray(const Array
<LoadedImage
>& loadedList
, ImageNum imageNum
);
299 static void buildLoadOrderRecurse(Array
<LoadedImage
>& loadedList
, const Array
<const ImageArray
*>& imagesArrays
, const Image
* toAdd
);
300 void invalidateInitializerRoots();
301 Image
::ResolvedSymbolTarget
makeResolvedTarget(const FixupTarget
& target
) const;
303 // MachOAnalyzerSet implementations
304 void mas_forEachImage(void (^handler
)(const WrappedMachO
& anImage
, bool hidden
, bool& stop
)) const override
;
305 bool mas_fromImageWeakDefLookup(const WrappedMachO
& fromWmo
, const char* symbolName
, uint64_t addend
, CachePatchHandler patcher
, FixupTarget
& target
) const override
;
306 void mas_mainExecutable(WrappedMachO
& anImage
) const override
;
307 void* mas_dyldCache() const override
;
308 bool wmo_dependent(const WrappedMachO
* image
, uint32_t depIndex
, WrappedMachO
& childObj
, bool& missingWeakDylib
) const override
;
309 const char* wmo_path(const WrappedMachO
* image
) const override
;
310 ExportsTrie
wmo_getExportsTrie(const WrappedMachO
* image
) const override
;
311 bool wmo_missingSymbolResolver(const WrappedMachO
* fromWmo
, bool weakImport
, bool lazyBind
, const char* symbolName
, const char* expectedInDylibPath
, const char* clientPath
, FixupTarget
& target
) const override
;
314 const FileSystem
& _fileSystem
;
315 const RootsChecker
& _rootsChecker
;
316 const DyldSharedCache
* const _dyldCache
;
317 const PathOverrides
& _pathOverrides
;
318 const GradedArchs
& _archs
;
319 Platform
const _platform
;
320 uint32_t const _startImageNum
;
321 const ImageArray
* _dyldImageArray
= nullptr;
322 DylibFixupHandler _dylibFixupHandler
= nullptr;
323 const Array
<CachedDylibAlias
>* _aliases
= nullptr;
324 const AtPath _atPathHandling
= AtPath
::none
;
325 uint32_t _mainProgLoadIndex
= 0;
326 const char* _mainProgLoadPath
= nullptr;
328 LaunchErrorInfo
* _launchErrorInfo
= nullptr;
329 mutable PathPool
* _tempPaths
= nullptr;
330 PathPool
* _mustBeMissingPaths
= nullptr;
331 OverflowSafeArray
<SkippedFile
> _skippedFiles
;
332 uint32_t _nextIndex
= 0;
333 OverflowSafeArray
<BuilderLoadedImage
,2048> _loadedImages
;
334 OverflowSafeArray
<Image
::LinkedImage
,65536> _dependencies
; // all dylibs in cache need ~20,000 edges
335 OverflowSafeArray
<InterposingTuple
> _interposingTuples
;
336 OverflowSafeArray
<Closure
::PatchEntry
> _weakDefCacheOverrides
;
337 OverflowSafeArray
<uint8_t> _objcSelectorsHashTable
;
338 OverflowSafeArray
<Image
::ObjCSelectorImage
> _objcSelectorsHashTableImages
;
339 OverflowSafeArray
<uint8_t> _objcClassesHashTable
;
340 OverflowSafeArray
<uint8_t> _objcProtocolsHashTable
;
341 OverflowSafeArray
<Image
::ObjCClassImage
> _objcClassesHashTableImages
;
342 OverflowSafeArray
<uint8_t> _objcClassesDuplicatesHashTable
;
343 PathPool
* _objcDuplicateClassWarnings
= nullptr;
344 uint32_t _alreadyInitedIndex
= 0;
345 bool _isLaunchClosure
= false;
346 bool _makingDyldCacheImages
= false;
347 bool _dyldCacheIsLive
= false; // means kernel is rebasing dyld cache content being viewed
348 bool _makingClosuresInCache
= false;
349 bool _allowRelativePaths
= false;
350 bool _atPathUsed
= false;
351 bool _interposingTuplesUsed
= false;
352 bool _fallbackPathUsed
= false;
353 bool _allowMissingLazies
= false;
354 bool _dyldCacheInvalidFormatVersion
= false;
355 bool _foundNonCachedImage
= false; // true means we have one or more images from disk we need to build closure(s) for
356 bool _foundDyldCacheRoots
= false; // true if one or more images are roots of the shared cache
357 bool _foundMissingLazyBinds
= false; // true if one or more images having missing lazy binds
358 bool _makeMinimalClosure
= false;
359 bool _interposingDisabled
= false;
360 bool _leaveRebasesAsOpcodes
= false;
361 ImageNum _libDyldImageNum
= 0;
362 ImageNum _libSystemImageNum
= 0;
365 class VIS_HIDDEN RebasePatternBuilder
368 RebasePatternBuilder(OverflowSafeArray
<closure
::Image
::RebasePattern
>& entriesStorage
, uint64_t ptrSize
);
369 void add(uint64_t runtimeOffset
);
371 OverflowSafeArray
<closure
::Image
::RebasePattern
>& _rebaseEntries
;
372 uint64_t _lastLocation
;
373 const uint64_t _ptrSize
;
375 static const Image
::RebasePattern _s_maxLeapPattern
;
376 static const uint64_t _s_maxLeapCount
;
380 class VIS_HIDDEN BindPatternBuilder
383 BindPatternBuilder(OverflowSafeArray
<closure
::Image
::BindPattern
>& entriesStorage
, uint64_t ptrSize
);
384 void add(uint64_t runtimeOffset
, Image
::ResolvedSymbolTarget target
, bool weakBindCoalese
);
386 OverflowSafeArray
<closure
::Image
::BindPattern
>& _bindEntries
;
387 const uint64_t _ptrSize
;
388 uint64_t _lastOffset
;
389 Image
::ResolvedSymbolTarget _lastTarget
;
393 } // namespace closure
397 #endif /* ClosureBuilder_h */