]>
Commit | Line | Data |
---|---|---|
10b92d3b A |
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 | ||
26 | #ifndef LaunchCacheFormat_h | |
27 | #define LaunchCacheFormat_h | |
28 | ||
29 | ||
30 | #include <stdint.h> | |
31 | #include <assert.h> | |
32 | #include <uuid/uuid.h> | |
33 | #include <mach/mach.h> | |
34 | ||
35 | #include "LaunchCache.h" | |
36 | ||
37 | ||
38 | namespace dyld3 { | |
39 | namespace launch_cache { | |
40 | namespace binary_format { | |
41 | ||
42 | ||
43 | // bump this number each time binary format changes | |
44 | enum { kFormatVersion = 8 }; | |
45 | ||
46 | union VIS_HIDDEN ImageRef { | |
47 | ImageRef() : val(0xFFFFFFFF) { } | |
48 | ImageRef(uint8_t kind, uint32_t groupNum, uint32_t indexInGroup) : _linkKind(kind), _groupNum(groupNum), _indexInGroup(indexInGroup) { | |
49 | assert(groupNum < (1 << 18)); | |
50 | assert(indexInGroup < (1 << 12)); | |
51 | } | |
52 | uint8_t kind() const { return _linkKind; } | |
53 | uint32_t groupNum() const { return _groupNum; } | |
54 | uint32_t indexInGroup() const { return _indexInGroup; } | |
55 | uint16_t value() const { return val; } | |
56 | void clearKind() { _linkKind = 0; } | |
57 | ||
58 | bool operator==(const ImageRef& rhs) const { | |
59 | return (val == rhs.val); | |
60 | } | |
61 | bool operator!=(const ImageRef& rhs) const { | |
62 | return (val != rhs.val); | |
63 | } | |
64 | static ImageRef weakImportMissing(); | |
65 | static ImageRef makeEmptyImageRef() { return ImageRef(); } | |
66 | ||
67 | private: | |
68 | ImageRef(uint32_t v) : val(v) { } | |
69 | ||
70 | uint32_t val; | |
71 | struct { | |
72 | uint32_t _linkKind : 2, // Image::LinkKind | |
73 | _groupNum : 18, // 0 => cached dylib group, 1 => other dylib group, 2 => main closure, etc | |
74 | _indexInGroup : 12; // max 64K images in group | |
75 | }; | |
76 | }; | |
77 | ||
78 | ||
79 | ||
80 | ||
81 | // In disk based images, all segments are multiples of page size | |
82 | // This struct just tracks the size (disk and vm) of each segment. | |
83 | // This is compact for most every image which have contiguous segments. | |
84 | // If the image does not have contiguous segments (rare), an extra | |
85 | // DiskSegment is inserted with the paddingNotSeg bit set. | |
86 | struct DiskSegment | |
87 | { | |
88 | uint64_t filePageCount : 30, | |
89 | vmPageCount : 30, | |
90 | permissions : 3, | |
91 | paddingNotSeg : 1; | |
92 | }; | |
93 | ||
94 | ||
95 | // In cache DATA_DIRTY is not page aligned or sized | |
96 | // This struct allows segments with any alignment and up to 256MB in size | |
97 | struct DyldCacheSegment | |
98 | { | |
99 | uint64_t cacheOffset : 32, | |
100 | size : 28, | |
101 | permissions : 4; | |
102 | }; | |
103 | ||
104 | // When an Image is built on the device, the mtime and inode are recorded. | |
105 | // When built off device, the first 16 bytes of SHA1 of CodeDirectory is recorded. | |
106 | union FileInfo | |
107 | { | |
108 | struct { | |
109 | uint64_t mtime; | |
110 | uint64_t inode; | |
111 | } statInfo; | |
112 | struct { | |
113 | uint8_t bytes[16]; | |
114 | } cdHash16; | |
115 | }; | |
116 | ||
117 | struct Image | |
118 | { | |
119 | uint32_t isDiskImage : 1, // images are DiskImage - not Image | |
120 | isInvalid : 1, // an error occurred creating the info for this image | |
121 | has16KBpages : 1, | |
122 | hasTextRelocs : 1, | |
123 | hasObjC : 1, | |
124 | mayHavePlusLoads : 1, | |
125 | isEncrypted : 1, // image is DSMOS or FairPlay encrypted | |
126 | hasWeakDefs : 1, | |
127 | neverUnload : 1, | |
128 | cwdSameAsThis : 1, // dylibs use file system relative paths, cwd must be main's dir | |
129 | isPlatformBinary : 1, // part of OS - can be loaded into LV process | |
130 | isBundle : 1, | |
131 | overridableDylib : 1, // only applicable to group 0 | |
132 | padding : 7, | |
133 | maxLoadCount : 12; | |
134 | int32_t groupOffset; // back pointer to containing ImageGroup (from start of Image) | |
135 | uint32_t pathPoolOffset; | |
136 | uint32_t pathHash; | |
137 | FileInfo fileInfo; | |
138 | uuid_t uuid; | |
139 | uint16_t dependentsArrayStartIndex; | |
140 | uint16_t dependentsArrayCount; | |
141 | uint16_t segmentsArrayStartIndex; | |
142 | uint16_t segmentsArrayCount; | |
143 | uint16_t initBeforeArrayStartIndex; | |
144 | uint16_t initBeforeArrayCount; | |
145 | uint16_t initOffsetsArrayStartIndex; | |
146 | uint16_t initOffsetsArrayCount; | |
147 | uint16_t dofOffsetsArrayStartIndex; | |
148 | uint16_t dofOffsetsArrayCount; | |
149 | }; | |
150 | ||
151 | // an image in the dyld shared cache | |
152 | struct CachedImage : public Image | |
153 | { | |
154 | uint32_t patchStartIndex; | |
155 | uint32_t patchCount; | |
156 | }; | |
157 | ||
158 | // an image not in the dyld shared cache (loaded from disk at runtime) | |
159 | struct DiskImage : public Image | |
160 | { | |
161 | uint32_t totalVmPages; | |
162 | uint32_t sliceOffsetIn4K; | |
163 | uint32_t codeSignFileOffset; | |
164 | uint32_t codeSignFileSize; | |
165 | uint32_t fixupsPoolOffset : 28, // offset in ImageGroup's pool for AllFixupsBySegment | |
166 | fixupsPoolSegCount : 4; // count of segments in AllFixupsBySegment for this image | |
167 | uint32_t fairPlayTextPageCount : 28, | |
168 | fairPlayTextStartPage : 4; | |
169 | uint32_t targetsArrayStartIndex; // index in ImageGroup's pool of OrdinalEntry | |
170 | uint32_t targetsArrayCount; | |
171 | }; | |
172 | ||
173 | ||
174 | // if an Image has an alias (symlink to it), the Image does not record the alias, but the ImageGroup does | |
175 | struct AliasEntry | |
176 | { | |
177 | uint32_t aliasHash; | |
178 | uint32_t imageIndexInGroup; | |
179 | uint32_t aliasOffsetInStringPool; | |
180 | }; | |
181 | ||
182 | // each DiskImage points to an array of these, one per segment with fixups | |
183 | struct AllFixupsBySegment | |
184 | { | |
185 | uint32_t segIndex : 4, | |
186 | offset : 28; // from start of AllFixupsBySegment to this seg's SegmentFixupsByPage | |
187 | }; | |
188 | ||
189 | ||
190 | // This struct is suitable for passing into kernel when kernel supports fixups on page-in. | |
191 | struct SegmentFixupsByPage | |
192 | { | |
193 | uint32_t size; // of this struct, including fixup opcodes | |
194 | uint32_t pageSize; // 0x1000 or 0x4000 | |
195 | uint32_t pageCount; | |
196 | uint32_t pageInfoOffsets[1]; // array size is pageCount | |
197 | // each page info is a FixUpOpcode[] | |
198 | }; | |
199 | ||
200 | enum class FixUpOpcode : uint8_t { | |
201 | done = 0x00, | |
202 | // apply = 0x10, | |
203 | rebase32 = 0x10, // add32 slide at current pageOffset, increment pageOffset by 4 | |
204 | rebase64 = 0x11, // add64 slide at current pageOffset, increment pageOffset by 8 | |
205 | bind32 = 0x12, // set 32-bit ordinal value at current pageOffset, increment pageOffset by 4 | |
206 | bind64 = 0x13, // set 64-bit ordinal value at current pageOffset, increment pageOffset by 8 | |
207 | rebaseText32 = 0x14, // add32 slide at current text pageOffset, increment pageOffset by 4 | |
208 | bindText32 = 0x15, // set 32-bit ordinal value at current text pageOffset, increment pageOffset by 4 | |
209 | bindTextRel32 = 0x16, // set delta to 32-bit ordinal value at current text pageOffset, increment pageOffset by 4 (i386 CALL to dylib) | |
210 | bindImportJmp32 = 0x17, // set delta to 32-bit ordinal value at current text pageOffset, increment pageOffset by 4 (i386 JMP to dylib) | |
211 | // fixupChain64 = 0x18, // current page offset is start of a chain of locations to fix up | |
212 | // adjPageOffset = 0x20, | |
213 | setPageOffset = 0x20, // low 4-bits is amount to increment (1 to 15). If zero, then add next ULEB (note: can set offset for unaligned pointer) | |
214 | incPageOffset = 0x30, // low 4-bits *4 is amount to increment (4 to 60). If zero, then add next ULEB * 4 | |
215 | // adjOrdinal = 0x40, | |
216 | setOrdinal = 0x40, // low 4-bits is ordinal (1-15). If zero, then ordinal is next ULEB | |
217 | incOrdinal = 0x50, // low 4-bits is ordinal inc amount (1-15). If zero, then ordinal is next ULEB | |
218 | repeat = 0x60 // low 5-bits is how many next bytes to repeat. next ULEB is repeat count | |
219 | }; | |
220 | ||
221 | // If a closure uses DYLD_LIBRARY_PATH to override an OS dylib, there is an | |
222 | // ImageRefOverride entry to redirect uses of the OS dylib. | |
223 | struct ImageRefOverride | |
224 | { | |
225 | ImageRef standardDylib; | |
226 | ImageRef overrideDylib; | |
227 | }; | |
228 | ||
229 | // If a closure interposes on, or has a dylib that overrides, something in the dyld shared cache, | |
230 | // then closure's ImageGroup contains an array of these | |
231 | struct DyldCacheOverride | |
232 | { | |
233 | uint64_t patchTableIndex : 24, // index into PatchTable array of group 0 | |
234 | imageIndex : 8, // index in this group (2) of what to replace with | |
235 | imageOffset : 32; // offset within image to override something in cache | |
236 | }; | |
237 | ||
238 | ||
239 | // The ImageGroup for the dyld shared cache dylibs contains and array of these | |
240 | // with one entry for each symbol in a cached dylib that is used by some other cached dylib. | |
241 | struct PatchTable | |
242 | { | |
243 | uint32_t targetCacheOffset; // delta from the base address of the cache to the address of the symbol to patch | |
244 | uint32_t offsetsStartIndex; // index into the PatchOffset array of first location to patch, last offset has low bit set | |
245 | }; | |
246 | ||
247 | struct PatchOffset | |
248 | { | |
249 | uint32_t last : 1, | |
250 | hasAddend : 1, | |
251 | dataRegionOffset : 30; | |
252 | }; | |
253 | ||
254 | struct ImageGroup | |
255 | { | |
256 | uint32_t imagesEntrySize : 8, | |
257 | dylibsExpectedOnDisk : 1, | |
258 | imageFileInfoIsCdHash : 1, | |
259 | padding : 14; | |
260 | uint32_t groupNum; | |
261 | uint32_t imagesPoolCount; | |
262 | uint32_t imagesPoolOffset; // offset to array of Image or DiskImage | |
263 | uint32_t imageAliasCount; | |
264 | uint32_t imageAliasOffset; // offset to array of AliasEntry | |
265 | uint32_t segmentsPoolCount; | |
266 | uint32_t segmentsPoolOffset; // offset to array of Segment or DyldCacheSegment | |
267 | uint32_t dependentsPoolCount; | |
268 | uint32_t dependentsPoolOffset; // offset to array of ImageRef | |
269 | uint32_t intializerOffsetPoolCount; | |
270 | uint32_t intializerOffsetPoolOffset; // offset to array of uint32_t | |
271 | uint32_t intializerListPoolCount; | |
272 | uint32_t intializerListPoolOffset; // offset to array of ImageRef | |
273 | uint32_t targetsPoolCount; | |
274 | uint32_t targetsOffset; // offset to array of TargetSymbolValue | |
275 | uint32_t fixupsPoolSize; | |
276 | uint32_t fixupsOffset; // offset to list of AllFixupsBySegment | |
277 | uint32_t cachePatchTableCount; | |
278 | uint32_t cachePatchTableOffset; // offset to array of PatchTable (used only in group 0) | |
279 | uint32_t cachePatchOffsetsCount; | |
280 | uint32_t cachePatchOffsetsOffset; // offset to array of PatchOffset cache offsets (used only in group 0) | |
281 | uint32_t symbolOverrideTableCount; | |
282 | uint32_t symbolOverrideTableOffset; // offset to array of DyldCacheOverride (used only in group 2) | |
283 | uint32_t imageOverrideTableCount; | |
284 | uint32_t imageOverrideTableOffset; // offset to array of ImageRefOverride (used only in group 2) | |
285 | uint32_t dofOffsetPoolCount; | |
286 | uint32_t dofOffsetPoolOffset; // offset to array of uint32_t | |
287 | uint32_t indirectGroupNumPoolCount; | |
288 | uint32_t indirectGroupNumPoolOffset; // offset to array of uint32_t | |
289 | uint32_t stringsPoolSize; | |
290 | uint32_t stringsPoolOffset; | |
291 | // Image array | |
292 | // Alias array | |
293 | // Segment array | |
294 | // ImageRef array | |
295 | // Initializer offsets array | |
296 | // Initializer ImageRef array | |
297 | // TargetSymbolValue array | |
298 | // AllFixupsBySegment pool | |
299 | // PatchTable array | |
300 | // PatchOffset array | |
301 | // DyldCacheOverride array | |
302 | // ImageRefOverride array | |
303 | // string pool | |
304 | // DOF offsets array | |
305 | }; | |
306 | ||
307 | ||
308 | struct Closure | |
309 | { | |
310 | enum { magicV1 = 0x31646c6e }; | |
311 | ||
312 | uint32_t magic; | |
313 | uint32_t usesCRT : 1, | |
314 | isRestricted : 1, | |
315 | usesLibraryValidation : 1, | |
316 | padding : 29; | |
317 | uint32_t missingFileComponentsOffset; // offset to array of 16-bit string pool offset of path components | |
318 | uint32_t dyldEnvVarsOffset; | |
319 | uint32_t dyldEnvVarsCount; | |
320 | uint32_t stringPoolOffset; | |
321 | uint32_t stringPoolSize; | |
322 | ImageRef libSystemRef; | |
323 | ImageRef libDyldRef; | |
324 | uint32_t libdyldVectorOffset; | |
325 | uint32_t mainExecutableIndexInGroup; | |
326 | uint32_t mainExecutableEntryOffset; | |
327 | uint32_t initialImageCount; | |
328 | uuid_t dyldCacheUUID; // all zero if this closure is embedded in a dyld cache | |
329 | uint8_t mainExecutableCdHash[20]; // or UUID if not code signed | |
330 | ImageGroup group; | |
331 | // MissingFile array | |
332 | // env vars array | |
333 | // string pool | |
334 | }; | |
335 | ||
336 | ||
337 | ||
338 | } // namespace binary_format | |
339 | ||
340 | } // namespace launch_cache | |
341 | } // namespace dyld | |
342 | ||
343 | ||
344 | #endif // LaunchCacheFormat_h | |
345 | ||
346 |