dyld-519.2.1.tar.gz
[apple/dyld.git] / dyld3 / LaunchCache.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 LaunchCache_h
26 #define LaunchCache_h
27
28
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <assert.h>
32 #include <uuid/uuid.h>
33 #include <mach/mach.h>
34 #include <mach-o/loader.h>
35
36 #if !DYLD_IN_PROCESS
37 #include <vector>
38 #include <unordered_set>
39 #include <string>
40 #include "shared-cache/DyldSharedCache.h"
41 #endif
42
43 #include "Diagnostics.h"
44
45 #define VIS_HIDDEN __attribute__((visibility("hidden")))
46
47
48 namespace dyld3 {
49
50 class DyldCacheParser;
51
52 namespace launch_cache {
53
54
55 namespace binary_format {
56 struct Image;
57 struct ImageGroup;
58 union ImageRef;
59 struct Closure;
60 struct DiskImage;
61 struct CachedImage;
62 struct AllFixupsBySegment;
63 struct SegmentFixupsByPage;
64 }
65
66 typedef binary_format::Image BinaryImageData;
67 typedef binary_format::ImageGroup BinaryImageGroupData;
68 typedef binary_format::Closure BinaryClosureData;
69
70
71 struct VIS_HIDDEN MemoryRange
72 {
73 bool contains(const MemoryRange& other) const;
74 bool intersects(const MemoryRange& other) const;
75
76 const void* address;
77 uint64_t size;
78 };
79
80
81 class VIS_HIDDEN SlowLoadSet
82 {
83 public:
84 SlowLoadSet(const BinaryImageData** start, const BinaryImageData** end) : _start(start), _end(end), _current(start) { }
85 bool contains(const BinaryImageData*);
86 bool add(const BinaryImageData*);
87 void forEach(void (^handler)(const BinaryImageData*));
88 void forEach(void (^handler)(const BinaryImageData*, bool& stop));
89 long count() const;
90 private:
91 const BinaryImageData** const _start;
92 const BinaryImageData** const _end;
93 const BinaryImageData** _current;
94 };
95
96 struct ImageGroup;
97
98
99 template <typename T>
100 class VIS_HIDDEN DynArray
101 {
102 public:
103 DynArray(uintptr_t count, T* storage) : _count(count), _elements(storage) { }
104 #if !DYLD_IN_PROCESS
105 DynArray(const std::vector<T>& vec) : _count(vec.size()), _elements((T*)&vec[0]) { }
106 #endif
107
108 T& operator[](size_t idx) { assert(idx < _count); return _elements[idx]; }
109 const T& operator[](size_t idx) const { assert(idx < _count); return _elements[idx]; }
110 uintptr_t count() const { return _count; }
111 private:
112 uintptr_t _count;
113 T* _elements;
114 };
115
116
117 // STACK_ALLOC_DYNARRAY(foo, 10, myarray);
118 #define STACK_ALLOC_DYNARRAY(_type, _count, _name) \
119 uintptr_t __##_name##_array_alloc[1 + ((sizeof(_type)*(_count))/sizeof(uintptr_t))]; \
120 dyld3::launch_cache::DynArray<_type> _name(_count, (_type*)__##_name##_array_alloc);
121
122
123 typedef DynArray<const BinaryImageGroupData*> ImageGroupList;
124
125
126 // In the pre-computed fixups for an Image, each fixup location is set to a TargetSymbolValue
127 // which is an abstract encoding of a resolved symbol in an image that can be turned into a
128 // real address once all ASLR slides are known.
129 struct VIS_HIDDEN TargetSymbolValue
130 {
131 #if DYLD_IN_PROCESS
132 class LoadedImages
133 {
134 public:
135 virtual const uint8_t* dyldCacheLoadAddressForImage() = 0;
136 virtual const mach_header* loadAddressFromGroupAndIndex(uint32_t groupNum, uint32_t indexInGroup) = 0;
137 virtual void forEachImage(void (^handler)(uint32_t anIndex, const BinaryImageData*, const mach_header*, bool& stop)) = 0;
138 virtual void setAsNeverUnload(uint32_t anIndex) = 0;
139 };
140
141 uintptr_t resolveTarget(Diagnostics& diag, const ImageGroup& inGroup, LoadedImages& images) const;
142 #else
143 static TargetSymbolValue makeInvalid();
144 static TargetSymbolValue makeAbsolute(uint64_t value);
145 static TargetSymbolValue makeSharedCacheOffset(uint32_t offset);
146 static TargetSymbolValue makeGroupValue(uint32_t groupIndex, uint32_t imageIndexInGroup, uint64_t offsetInImage, bool isIndirectGroupNum);
147 static TargetSymbolValue makeDynamicGroupValue(uint32_t imagePathPoolOffset, uint32_t imageSymbolPoolOffset, bool weakImport);
148 std::string asString(ImageGroup group) const;
149 bool operator==(const TargetSymbolValue& other) const { return (_data.raw == other._data.raw); }
150 bool isSharedCacheTarget(uint64_t& offsetInCache) const;
151 bool isGroupImageTarget(uint32_t& groupNum, uint32_t& indexInGroup, uint64_t& offsetInImage) const;
152 bool isInvalid() const;
153 #endif
154 private:
155 TargetSymbolValue();
156
157 enum Kinds { kindSharedCache, kindAbsolute, kindGroup, kindDynamicGroup };
158
159
160 struct SharedCacheOffsetTarget {
161 uint64_t kind : 2, // kindSharedCache
162 offsetIntoCache : 62;
163 };
164 struct AbsoluteTarget {
165 uint64_t kind : 2, // kindAbsolute
166 value : 62;
167 };
168 struct GroupImageTarget {
169 uint64_t kind : 2, // kindGroup
170 isIndirectGroup : 1, // 0 => use groupNum directly. 1 => index indirect side table
171 groupNum : 7, // 0 not used, 1 => other dylibs, 2 => main closure, 3 => first dlopen group
172 indexInGroup : 12,
173 offsetInImage : 42;
174 };
175 struct DynamicGroupImageTarget {
176 uint64_t kind : 2, // kindDynamicGroup
177 weakImport : 1,
178 imagePathOffset : 30,
179 symbolNameOffset: 31;
180 };
181 union {
182 SharedCacheOffsetTarget sharedCache;
183 AbsoluteTarget absolute;
184 GroupImageTarget group;
185 DynamicGroupImageTarget dynamicGroup;
186 uint64_t raw;
187 } _data;
188
189 static_assert(sizeof(_data) == 8, "Overflow in size of TargetSymbolValue");
190 };
191
192
193 struct VIS_HIDDEN Image
194 {
195 enum class LinkKind { regular=0, weak=1, upward=2, reExport=3 };
196 enum class FixupKind { rebase32, rebase64, bind32, bind64, rebaseText32, bindText32, bindTextRel32, bindImportJmp32 };
197
198 Image(const BinaryImageData* binaryData) : _binaryData(binaryData) { }
199
200 bool valid() const { return (_binaryData != nullptr); }
201 const BinaryImageData* binaryData() const { return _binaryData; }
202 const ImageGroup group() const;
203 uint32_t maxLoadCount() const;
204 const char* path() const;
205 const char* leafName() const;
206 uint32_t pathHash() const;
207 const uuid_t* uuid() const;
208 bool isInvalid() const;
209 bool hasObjC() const;
210 bool isBundle() const;
211 bool hasWeakDefs() const;
212 bool mayHavePlusLoads() const;
213 bool hasTextRelocs() const;
214 bool neverUnload() const;
215 bool cwdMustBeThisDir() const;
216 bool isPlatformBinary() const;
217 bool overridableDylib() const;
218 bool validateUsingModTimeAndInode() const;
219 bool validateUsingCdHash() const;
220 uint64_t fileModTime() const;
221 uint64_t fileINode() const;
222 const uint8_t* cdHash16() const;
223 void forEachDependentImage(const ImageGroupList& groups, void (^handler)(uint32_t depIndex, Image depImage, LinkKind kind, bool& stop)) const;
224 #if !DYLD_IN_PROCESS
225 bool recurseAllDependentImages(const ImageGroupList& groups, std::unordered_set<const BinaryImageData*>& allDependents) const;
226 #endif
227 bool recurseAllDependentImages(const ImageGroupList& groups, SlowLoadSet& allDependents,
228 void (^handler)(const dyld3::launch_cache::binary_format::Image* aBinImage, bool& stop)) const;
229 bool containsAddress(const void* addr, const void* imageLoadAddress, uint8_t* permissions) const;
230 bool segmentHasFixups(uint32_t segIndex) const;
231 void forEachInitializer(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
232 void forEachInitBefore(const ImageGroupList& groups, void (^handler)(Image imageToInit)) const;
233 void forEachInitBefore(void (^handler)(binary_format::ImageRef imageToInit)) const;
234 void forEachDOF(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
235
236 bool isDiskImage() const;
237
238 // the following are only valid if isDiskImage() returns false
239 const binary_format::CachedImage* asCachedImage() const;
240 uint32_t cacheOffset() const;
241 uint32_t patchStartIndex() const;
242 uint32_t patchCount() const;
243
244
245 // the following are only valid if isDiskImage() returns true
246 const binary_format::DiskImage* asDiskImage() const;
247 uint64_t sliceOffsetInFile() const;
248 bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const;
249 bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const;
250 uint64_t vmSizeToMap() const;
251 void forEachDiskSegment(void (^handler)(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const;
252 void forEachCacheSegment(void (^handler)(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const;
253 void forEachFixup(uint32_t segIndex, MemoryRange segContent,
254 void (^handler)(uint64_t segOffset, FixupKind kind, TargetSymbolValue value, bool& stop)) const;
255
256 #if !DYLD_IN_PROCESS
257 void printAsJSON(const ImageGroupList& groupList, bool printFixups=false, bool printDependentsDetails=false, FILE* out=stdout) const;
258 #endif
259
260 // todo: fairPlayTextPages
261
262 private:
263 friend struct ImageGroup;
264 friend struct Closure;
265
266 bool recurseAllDependentImages(const ImageGroupList& groups, SlowLoadSet& allDependents, bool& stopped,
267 void (^handler)(const dyld3::launch_cache::binary_format::Image* aBinImage, bool& stop)) const;
268 uint32_t pageSize() const;
269 const binary_format::SegmentFixupsByPage* segmentFixups(uint32_t segIndex) const;
270 static void forEachFixup(const uint8_t* pageFixups, const void* segContent, uint32_t& offset, uint32_t& ordinal,
271 void (^handler)(uint32_t pageOffset, FixupKind kind, uint32_t targetOrdinal, bool& stop));
272 static Image resolveImageRef(const ImageGroupList& groups, binary_format::ImageRef ref, bool applyOverrides=true);
273
274
275 const BinaryImageData* _binaryData;
276 };
277
278
279 struct VIS_HIDDEN ImageGroup
280 {
281 ImageGroup(const BinaryImageGroupData* binaryData) : _binaryData(binaryData) { }
282
283 size_t size() const;
284 uint32_t imageCount() const;
285 uint32_t groupNum() const;
286 bool dylibsExpectedOnDisk() const;
287 const Image image(uint32_t index) const;
288 uint32_t indexInGroup(const BinaryImageData* image) const;
289 const BinaryImageData* findImageByPath(const char* path, uint32_t& foundIndex) const;
290 const BinaryImageData* findImageByCacheOffset(size_t cacheVmOffset, uint32_t& mhCacheOffset, uint8_t& foundPermissions) const;
291 const BinaryImageData* imageBinary(uint32_t index) const;
292 binary_format::ImageRef dependentPool(uint32_t index) const;
293 const BinaryImageGroupData* binaryData() const { return _binaryData; }
294 const char* stringFromPool(uint32_t offset) const;
295 uint32_t indirectGroupNum(uint32_t index) const;
296 void forEachImageRefOverride(void (^handler)(binary_format::ImageRef standardDylibRef, binary_format::ImageRef overrideDyilbRef, bool& stop)) const;
297 void forEachImageRefOverride(const ImageGroupList& groupList, void (^handler)(Image standardDylib, Image overrideDyilb, bool& stop)) const;
298 void forEachAliasOf(uint32_t imageIndex, void (^handler)(const char* aliasPath, uint32_t aliasPathHash, bool& stop)) const;
299 #if DYLD_IN_PROCESS
300 void forEachDyldCacheSymbolOverride(void (^handler)(uint32_t patchTableIndex, const BinaryImageData* image, uint32_t imageOffset, bool& stop)) const;
301 void forEachDyldCachePatchLocation(const void* dyldCacheLoadAddress, uint32_t patchTargetIndex,
302 void (^handler)(uintptr_t* locationToPatch, uintptr_t addend, bool& stop)) const;
303 #else
304 void forEachDyldCacheSymbolOverride(void (^handler)(uint32_t patchTableIndex, uint32_t imageIndexInClosure, uint32_t imageOffset, bool& stop)) const;
305 void forEachDyldCachePatchLocation(const DyldCacheParser& cacheParser, void (^handler)(uint32_t targetCacheOffset, const std::vector<uint32_t>& usesPointersCacheOffsets, bool& stop)) const;
306 bool hasPatchTableIndex(uint32_t targetCacheOffset, uint32_t& index) const;
307 #endif
308
309 static uint32_t hashFunction(const char* s);
310 #if !DYLD_IN_PROCESS
311 void printAsJSON(const ImageGroupList& groupList, bool printFixups=false, bool printDependentsDetails=false, FILE* out=stdout) const;
312 void printStatistics(FILE* out=stderr) const;
313 #endif
314
315 private:
316 friend struct Image;
317
318 const char* stringPool() const;
319 uint32_t stringPoolSize() const;
320 const uint64_t* segmentPool(uint32_t index) const;
321 const binary_format::AllFixupsBySegment* fixUps(uint32_t offset) const;
322 const TargetSymbolValue* targetValuesArray() const;
323 uint32_t targetValuesCount() const;
324 uint32_t initializersPoolCount() const;
325 const uint32_t* initializerOffsetsPool() const;
326 const uint32_t initializerOffsetsCount() const;
327 const binary_format::ImageRef* intializerListPool() const;
328 const uint32_t intializerListPoolCount() const;
329 const uint32_t* dofOffsetsPool() const;
330 const uint32_t dofOffsetsCount() const;
331 const uint32_t* indirectGroupNumsPool() const;
332 const uint32_t indirectGroupNumsCount() const;
333 void forEachDyldCachePatch(uint32_t patchTargetIndex, uint32_t cacheDataVmOffset,
334 void (^handler)(uint32_t targetCacheOffset, uint32_t usePointersCacheOffset, bool hasAddend, bool& stop)) const;
335
336 const BinaryImageGroupData* _binaryData;
337 };
338
339
340
341 struct VIS_HIDDEN Closure
342 {
343 Closure(const BinaryClosureData* binaryData);
344
345 size_t size() const;
346 const uuid_t* dyldCacheUUID() const;
347 const uint8_t* cdHash() const;
348 uint32_t initialImageCount() const;
349 uint32_t mainExecutableImageIndex() const;
350 uint32_t mainExecutableEntryOffset() const;
351 bool mainExecutableUsesCRT() const;
352 bool isRestricted() const;
353 bool usesLibraryValidation() const;
354 const BinaryImageData* libSystem(const ImageGroupList& groups);
355 const BinaryImageData* libDyld(const ImageGroupList& groups);
356 uint32_t libdyldVectorOffset() const;
357 const ImageGroup group() const;
358 const BinaryClosureData* binaryData() const { return _binaryData; }
359 void forEachMustBeMissingFile(void (^handler)(const char* path, bool& stop)) const;
360 void forEachEnvVar(void (^handler)(const char* keyEqualValue, bool& stop)) const;
361
362 #if !DYLD_IN_PROCESS
363 void printAsJSON(const ImageGroupList& groupList, bool printFixups=true, bool printDependentsDetails=false, FILE* out=stdout) const;
364 void printStatistics(FILE* out=stderr) const;
365 #endif
366
367 private:
368 const BinaryClosureData* _binaryData;
369 };
370
371
372
373
374
375
376 } // namespace launch_cache
377 } // namespace dyld3
378
379
380 #endif // LaunchCache_h
381
382