dyld-733.8.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 "Map.h"
36 #include "Loading.h"
37
38 #include <optional>
39
40 namespace objc_opt {
41 struct objc_clsopt_t;
42 struct objc_selopt_t;
43 struct objc_protocolopt2_t;
44 }
45
46 namespace dyld3 {
47
48
49 namespace closure {
50
51
52
53 class VIS_HIDDEN ClosureBuilder
54 {
55 public:
56
57 struct LaunchErrorInfo
58 {
59 uintptr_t kind;
60 const char* clientOfDylibPath;
61 const char* targetDylibPath;
62 const char* symbol;
63 };
64
65 struct ResolvedTargetInfo
66 {
67 const MachOLoaded* foundInDylib;
68 const char* requestedSymbolName;
69 const char* foundSymbolName;
70 uint64_t addend;
71 bool weakBindCoalese;
72 bool weakBindSameImage;
73 bool isWeakDef;
74 bool skippableWeakDef;
75 int libOrdinal;
76 };
77
78 struct CacheDylibsBindingHandlers
79 {
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);
83 };
84
85 enum class AtPath { none, all, onlyInRPaths };
86
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);
91 ~ClosureBuilder();
92 Diagnostics& diagnostics() { return _diag; }
93
94 const LaunchClosure* makeLaunchClosure(const LoadedFileInfo& fileInfo, bool allowInsertFailures);
95
96 const LaunchClosure* makeLaunchClosure(const char* mainPath,bool allowInsertFailures);
97
98
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);
103
104 ImageNum nextFreeImageNum() const { return _startImageNum + _nextIndex; }
105
106 void setDyldCacheInvalidFormatVersion();
107 void disableInterposing() { _interposingDisabled = true; }
108
109
110 struct PatchableExport
111 {
112 uint32_t cacheOffsetOfImpl;
113 uint32_t cacheOffsetOfName;
114 uint32_t patchLocationsCount;
115 const dyld_cache_patchable_location* patchLocations;
116 };
117
118 struct CachedDylibInfo
119 {
120 LoadedFileInfo fileInfo;
121 };
122
123 struct CachedDylibAlias
124 {
125 const char* realPath;
126 const char* aliasPath;
127 };
128
129 const ImageArray* makeDyldCacheImageArray(bool customerCache, const Array<CachedDylibInfo>& dylibs, const Array<CachedDylibAlias>& aliases);
130
131 const ImageArray* makeOtherDylibsImageArray(const Array<LoadedFileInfo>& otherDylibs, uint32_t cachedDylibsCount);
132
133 static void buildLoadOrder(Array<LoadedImage>& loadedList, const Array<const ImageArray*>& imagesArrays, const Closure* toAdd);
134
135 private:
136
137
138 struct InitInfo
139 {
140 uint32_t initOrder;
141 bool danglingUpward;
142 bool visited;
143 };
144
145 struct BuilderLoadedImage
146 {
147 Array<Image::LinkedImage> dependents;
148 ImageNum imageNum;
149 uint32_t unmapWhenDone : 1,
150 contentRebased : 1,
151 hasInits : 1,
152 markNeverUnload : 1,
153 rtldLocal : 1,
154 isBadImage : 1,
155 mustBuildClosure : 1,
156 hasMissingWeakImports : 1,
157 padding : 12,
158 overrideImageNum : 12;
159 LoadedFileInfo loadedFileInfo;
160
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; }
164 };
165
166 struct LoadedImageChain
167 {
168 LoadedImageChain* previous;
169 BuilderLoadedImage& image;
170 };
171
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
177 };
178
179 typedef LaunchClosure::SkippedFile SkippedFile;
180
181
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);
220
221 struct HashCString {
222 static size_t hash(const char* v);
223 };
224
225 struct EqualCString {
226 static bool equal(const char* s1, const char* s2);
227 };
228
229 struct HashPointer {
230 template<typename T>
231 static size_t hash(const T* v) {
232 return std::hash<const T*>{}(v);
233 }
234 };
235
236 struct EqualPointer {
237 template<typename T>
238 static bool equal(const T* s1, const T* s2) {
239 return s1 == s2;
240 }
241 };
242
243 struct ObjCOptimizerImage {
244
245 ObjCOptimizerImage() {
246 }
247
248 ~ObjCOptimizerImage() {
249 }
250
251 typedef std::pair<closure::Image::ObjCClassNameImageOffset, closure::Image::ObjCClassImageOffset> SeenClass;
252
253 struct SelectorFixup {
254 uint32_t fixupVMOffset;
255 bool isSharedCache;
256 union {
257 struct {
258 uint32_t selectorTableIndex;
259 } sharedCache;
260 struct {
261 const char* selectorString;
262 } image;
263 };
264 };
265
266 BuilderLoadedImage* loadedImage = nullptr;
267 ImageWriter* writer = nullptr;
268 uint64_t fairplayFileOffsetStart = 0;
269 uint64_t fairplayFileOffsetEnd = 0;
270 Diagnostics diag;
271
272 // Image info optimisation
273 uint64_t objcImageInfoVMOffset;
274
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;
282
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;
287 };
288
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);
301
302 void addDuplicateObjCClassWarning(const char* className,
303 const char* duplicateDefinitionPath,
304 const char* canonicalDefinitionPath);
305
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();
309
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;
322 Diagnostics _diag;
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;
358 };
359
360
361
362
363
364 } // namespace closure
365 } // namespace dyld3
366
367
368 #endif /* ClosureBuilder_h */