dyld-832.7.1.tar.gz
[apple/dyld.git] / dyld3 / ClosureBuilder.h
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #ifndef ClosureBuilder_h
26 #define ClosureBuilder_h
27
28
29 #include "Closure.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"
36 #include "Map.h"
37 #include "Loading.h"
38
39 #include <optional>
40
41 namespace objc_opt {
42 struct objc_clsopt_t;
43 struct objc_selopt_t;
44 struct objc_protocolopt2_t;
45 }
46
47 typedef dyld3::MachOAnalyzerSet::WrappedMachO WrappedMachO;
48
49 namespace dyld3 {
50
51 class RootsChecker;
52
53 namespace closure {
54
55 class ClosureAnalyzerSet;
56
57 class VIS_HIDDEN ClosureBuilder : public dyld3::MachOAnalyzerSet
58 {
59 public:
60
61 struct ResolvedTargetInfo
62 {
63 const MachOLoaded* foundInDylib;
64 const char* requestedSymbolName;
65 const char* foundSymbolName;
66 uint64_t addend;
67 bool weakBindCoalese;
68 bool weakBindSameImage;
69 bool isWeakDef;
70 bool skippableWeakDef;
71 int libOrdinal;
72 };
73
74 typedef void (^DylibFixupHandler)(const MachOLoaded* fixupIn, uint64_t fixupLocRuntimeOffset, PointerMetaData pmd, const MachOAnalyzerSet::FixupTarget& target);
75
76 enum class AtPath { none, all, onlyInRPaths };
77
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);
83 ~ClosureBuilder();
84 Diagnostics& diagnostics() { return _diag; }
85
86 const LaunchClosure* makeLaunchClosure(const LoadedFileInfo& fileInfo, bool allowInsertFailures);
87
88 const LaunchClosure* makeLaunchClosure(const char* mainPath,bool allowInsertFailures);
89 void makeMinimalClosures() { _makeMinimalClosure = true; }
90 void setCanSkipEncodingRebases() { _leaveRebasesAsOpcodes = true; }
91
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);
96
97 ImageNum nextFreeImageNum() const { return _startImageNum + _nextIndex; }
98 Platform platform() const { return _platform; }
99
100 void setDyldCacheInvalidFormatVersion();
101 void disableInterposing() { _interposingDisabled = true; }
102
103
104 struct PatchableExport
105 {
106 uint32_t cacheOffsetOfImpl;
107 uint32_t cacheOffsetOfName;
108 uint32_t patchLocationsCount;
109 const dyld_cache_patchable_location* patchLocations;
110 };
111
112 struct CachedDylibInfo
113 {
114 LoadedFileInfo fileInfo;
115 };
116
117 struct CachedDylibAlias
118 {
119 const char* realPath;
120 const char* aliasPath;
121 };
122
123 const ImageArray* makeDyldCacheImageArray(const Array<CachedDylibInfo>& dylibs, const Array<CachedDylibAlias>& aliases);
124
125 const ImageArray* makeOtherDylibsImageArray(const Array<LoadedFileInfo>& otherDylibs, uint32_t cachedDylibsCount);
126
127 static void buildLoadOrder(Array<LoadedImage>& loadedList, const Array<const ImageArray*>& imagesArrays, const Closure* toAdd);
128
129 private:
130 friend ClosureAnalyzerSet;
131
132 struct InitInfo
133 {
134 uint32_t initOrder : 30,
135 danglingUpward : 1,
136 visited : 1;
137 };
138
139 struct BuilderLoadedImage
140 {
141 Array<Image::LinkedImage> dependents;
142 ImageNum imageNum;
143 uint32_t unmapWhenDone : 1,
144 contentRebased : 1,
145 hasInits : 1,
146 markNeverUnload : 1,
147 rtldLocal : 1,
148 isBadImage : 1,
149 mustBuildClosure : 1,
150 hasMissingWeakImports : 1,
151 hasInterposingTuples : 1,
152 padding : 11,
153 overrideImageNum : 12;
154 uint32_t exportsTrieOffset;
155 uint32_t exportsTrieSize;
156 LoadedFileInfo loadedFileInfo;
157
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; }
161 };
162
163 struct LoadedImageChain
164 {
165 LoadedImageChain* previous;
166 BuilderLoadedImage& image;
167 };
168
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
174 };
175
176 typedef LaunchClosure::SkippedFile SkippedFile;
177
178
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);
208
209 struct HashCString {
210 static size_t hash(const char* v);
211 };
212
213 struct EqualCString {
214 static bool equal(const char* s1, const char* s2);
215 };
216
217 struct HashPointer {
218 template<typename T>
219 static size_t hash(const T* v) {
220 return std::hash<const T*>{}(v);
221 }
222 };
223
224 struct EqualPointer {
225 template<typename T>
226 static bool equal(const T* s1, const T* s2) {
227 return s1 == s2;
228 }
229 };
230
231 struct ObjCOptimizerImage {
232
233 ObjCOptimizerImage() {
234 }
235
236 ~ObjCOptimizerImage() {
237 }
238
239 typedef std::pair<closure::Image::ObjCClassNameImageOffset, closure::Image::ObjCClassImageOffset> SeenClass;
240
241 struct SelectorFixup {
242 uint32_t fixupVMOffset;
243 bool isSharedCache;
244 union {
245 struct {
246 uint32_t selectorTableIndex;
247 } sharedCache;
248 struct {
249 const char* selectorString;
250 } image;
251 };
252 };
253
254 BuilderLoadedImage* loadedImage = nullptr;
255 ImageWriter* writer = nullptr;
256 uint64_t fairplayFileOffsetStart = 0;
257 uint64_t fairplayFileOffsetEnd = 0;
258 Diagnostics diag;
259
260 // Image info optimisation
261 uint64_t objcImageInfoVMOffset;
262
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;
270
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;
276 };
277
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);
291
292 void addDuplicateObjCClassWarning(const char* className,
293 const char* duplicateDefinitionPath,
294 const char* canonicalDefinitionPath);
295
296 void parseObjCClassDuplicates(Map<const char*, bool, HashCString, EqualCString>& duplicateClassesToIgnore);
297
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;
302
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;
312
313
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;
327 Diagnostics _diag;
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;
363 };
364
365 class VIS_HIDDEN RebasePatternBuilder
366 {
367 public:
368 RebasePatternBuilder(OverflowSafeArray<closure::Image::RebasePattern>& entriesStorage, uint64_t ptrSize);
369 void add(uint64_t runtimeOffset);
370 private:
371 OverflowSafeArray<closure::Image::RebasePattern>& _rebaseEntries;
372 uint64_t _lastLocation;
373 const uint64_t _ptrSize;
374
375 static const Image::RebasePattern _s_maxLeapPattern;
376 static const uint64_t _s_maxLeapCount;
377 };
378
379
380 class VIS_HIDDEN BindPatternBuilder
381 {
382 public:
383 BindPatternBuilder(OverflowSafeArray<closure::Image::BindPattern>& entriesStorage, uint64_t ptrSize);
384 void add(uint64_t runtimeOffset, Image::ResolvedSymbolTarget target, bool weakBindCoalese);
385 private:
386 OverflowSafeArray<closure::Image::BindPattern>& _bindEntries;
387 const uint64_t _ptrSize;
388 uint64_t _lastOffset;
389 Image::ResolvedSymbolTarget _lastTarget;
390 };
391
392
393 } // namespace closure
394 } // namespace dyld3
395
396
397 #endif /* ClosureBuilder_h */