]> git.saurik.com Git - apple/dyld.git/blob - dyld3/Closure.h
dyld-733.6.tar.gz
[apple/dyld.git] / dyld3 / Closure.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 Closures_h
26 #define Closures_h
27
28
29 #include <stdint.h>
30 #include <assert.h>
31 #include <uuid/uuid.h>
32 #include <mach/mach.h>
33 #include <mach-o/loader.h>
34
35 #include "Diagnostics.h"
36 #include "Array.h"
37 #include "MachOLoaded.h"
38 #include "SupportedArchs.h"
39
40 namespace objc_opt {
41 struct objc_opt_t;
42 }
43
44 namespace dyld3 {
45 namespace closure {
46
47
48
49 // bump this number each time binary format changes
50 enum { kFormatVersion = 10 };
51
52
53 typedef uint32_t ImageNum;
54
55 const ImageNum kFirstDyldCacheImageNum = 0x00000001;
56 const ImageNum kLastDyldCacheImageNum = 0x00000FFF;
57 const ImageNum kFirstOtherOSImageNum = 0x00001001;
58 const ImageNum kLastOtherOSImageNum = 0x00001FFF;
59 const ImageNum kFirstLaunchClosureImageNum = 0x00002000;
60 const ImageNum kMissingWeakLinkedImage = 0x0FFFFFFF;
61
62 class ObjCSelectorOpt;
63 class ObjCClassOpt;
64 class ObjCClassDuplicatesOpt;
65
66 //
67 // Generic typed range of bytes (similar to load commands)
68 // Must be 4-byte aligned
69 //
70 struct VIS_HIDDEN TypedBytes
71 {
72 enum class Type : uint32_t {
73 // containers which have an overall length and TypedBytes inside their content
74 launchClosure = 1, // contains TypedBytes of closure attributes including imageArray
75 imageArray = 2, // sizeof(ImageArray) + sizeof(uint32_t)*count + size of all images
76 image = 3, // contains TypedBytes of image attributes
77 dlopenClosure = 4, // contains TypedBytes of closure attributes including imageArray
78
79 // attributes for Images
80 imageFlags = 7, // sizeof(Image::Flags)
81 pathWithHash = 8, // len = uint32_t + length path + 1, use multiple entries for aliases
82 fileInodeAndTime = 9, // sizeof(FileInfo)
83 cdHash = 10, // 20, use multiple entries on watchOS for all hashes
84 uuid = 11, // 16
85 mappingInfo = 12, // sizeof(MappingInfo)
86 diskSegment = 13, // sizeof(DiskSegment) * count
87 cacheSegment = 14, // sizeof(DyldCacheSegment) * count
88 dependents = 15, // sizeof(LinkedImage) * count
89 initOffsets = 16, // sizeof(uint32_t) * count
90 dofOffsets = 17, // sizeof(uint32_t) * count
91 codeSignLoc = 18, // sizeof(CodeSignatureLocation)
92 fairPlayLoc = 19, // sizeof(FairPlayRange)
93 rebaseFixups = 20, // sizeof(RebasePattern) * count
94 bindFixups = 21, // sizeof(BindPattern) * count
95 cachePatchInfo = 22, // deprecated
96 textFixups = 23, // sizeof(TextFixupPattern) * count
97 imageOverride = 24, // sizeof(ImageNum)
98 initBefores = 25, // sizeof(ImageNum) * count
99 initsSection = 26, // sizeof(InitializerSectionRange)
100 chainedFixupsTargets = 27, // sizeof(ResolvedSymbolTarget) * count
101 termOffsets = 28, // sizeof(uint32_t) * count
102 chainedStartsOffset = 29, // sizeof(uint64_t)
103 objcFixups = 30, // sizeof(ResolvedSymbolTarget) + (sizeof(uint32_t) * 2) + (sizeof(ProtocolISAFixup) * count) + (sizeof(SelectorReferenceFixup) * count)
104
105 // attributes for Closures (launch or dlopen)
106 closureFlags = 32, // sizeof(Closure::Flags)
107 dyldCacheUUID = 33, // 16
108 missingFiles = 34,
109 envVar = 35, // "DYLD_BLAH=stuff"
110 topImage = 36, // sizeof(ImageNum)
111 libDyldEntry = 37, // sizeof(ResolvedSymbolTarget)
112 libSystemNum = 38, // sizeof(ImageNum)
113 bootUUID = 39, // c-string 40
114 mainEntry = 40, // sizeof(ResolvedSymbolTarget)
115 startEntry = 41, // sizeof(ResolvedSymbolTarget) // used by programs built with crt1.o
116 cacheOverrides = 42, // sizeof(PatchEntry) * count // used if process uses interposing or roots (cached dylib overrides)
117 interposeTuples = 43, // sizeof(InterposingTuple) * count
118 existingFiles = 44, // uint64_t + (SkippedFiles * count)
119 selectorTable = 45, // uint32_t + (sizeof(ObjCSelectorImage) * count) + hashTable size
120 classTable = 46, // (3 * uint32_t) + (sizeof(ObjCClassImage) * count) + classHashTable size + protocolHashTable size
121 warning = 47, // len = uint32_t + length path + 1, use one entry per warning
122 duplicateClassesTable = 48, // duplicateClassesHashTable
123 };
124
125 Type type : 8;
126 uint32_t payloadLength : 24;
127
128 const void* payload() const;
129 void* payload();
130 };
131
132 static_assert(sizeof(TypedBytes) == 4, "Wrong size for TypedBytes");
133
134
135 //
136 // A TypedBytes which is a bag of other TypedBytes
137 //
138 struct VIS_HIDDEN ContainerTypedBytes : TypedBytes
139 {
140 void forEachAttribute(void (^callback)(const TypedBytes* typedBytes, bool& stop)) const;
141 void forEachAttributePayload(Type requestedType, void (^handler)(const void* payload, uint32_t size, bool& stop)) const;
142 const void* findAttributePayload(Type requestedType, uint32_t* payloadSize=nullptr) const;
143 private:
144 const TypedBytes* first() const;
145 const TypedBytes* next(const TypedBytes*) const;
146 };
147
148
149 //
150 // Information about a mach-o file
151 //
152 struct VIS_HIDDEN Image : ContainerTypedBytes
153 {
154 enum class LinkKind { regular=0, weak=1, upward=2, reExport=3 };
155
156 size_t size() const;
157 ImageNum imageNum() const;
158 bool representsImageNum(ImageNum num) const; // imageNum() or isOverrideOfDyldCacheImage()
159 uint32_t maxLoadCount() const;
160 const char* path() const;
161 const char* leafName() const;
162 bool getUuid(uuid_t) const;
163 bool isInvalid() const;
164 bool inDyldCache() const;
165 bool hasObjC() const;
166 bool hasInitializers() const;
167 bool hasPrecomputedObjC() const;
168 bool hasTerminators() const;
169 bool hasReadOnlyData() const;
170 bool hasChainedFixups() const;
171 bool isBundle() const;
172 bool isDylib() const;
173 bool isExecutable() const;
174 bool hasWeakDefs() const;
175 bool mayHavePlusLoads() const;
176 bool is64() const;
177 bool neverUnload() const;
178 bool cwdMustBeThisDir() const;
179 bool isPlatformBinary() const;
180 bool overridableDylib() const;
181 bool hasFileModTimeAndInode(uint64_t& inode, uint64_t& mTime) const;
182 void forEachCDHash(void (^handler)(const uint8_t cdHash[20], bool& stop)) const;
183 void forEachAlias(void (^handler)(const char* aliasPath, bool& stop)) const;
184 void forEachDependentImage(void (^handler)(uint32_t dependentIndex, LinkKind kind, ImageNum imageNum, bool& stop)) const;
185 ImageNum dependentImageNum(uint32_t depIndex) const;
186 bool containsAddress(const void* addr, const void* imageLoadAddress, uint8_t* permissions=nullptr) const;
187 bool forEachInitializerSection(void (^handler)(uint32_t sectionOffset, uint32_t sectionSize)) const;
188 void forEachInitializer(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
189 void forEachTerminator(const void* imageLoadAddress, void (^handler)(const void* terminator)) const;
190 void forEachImageToInitBefore(void (^handler)(ImageNum imageToInit, bool& stop)) const;
191 void forEachDOF(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
192 bool hasPathWithHash(const char* path, uint32_t hash) const;
193 bool isOverrideOfDyldCacheImage(ImageNum& cacheImageNum) const;
194 uint64_t textSize() const;
195
196 union ResolvedSymbolTarget
197 {
198 enum Kinds { kindRebase, kindSharedCache, kindImage, kindAbsolute };
199
200 struct Rebase {
201 uint64_t kind : 2, // kindRebase
202 unused : 62; // all zeros
203 };
204 struct SharedCache {
205 uint64_t kind : 2; // kindSharedCache
206 int64_t offset : 62;
207 };
208 struct Image {
209 uint64_t kind : 2, // kindImage
210 imageNum : 22; // ImageNum
211 int64_t offset : 40;
212 };
213 struct Absolute {
214 uint64_t kind : 2, // kindAbsolute
215 value : 62; // sign extended
216 };
217 Rebase rebase;
218 SharedCache sharedCache;
219 Image image;
220 Absolute absolute;
221 uint64_t raw;
222
223 bool operator==(const ResolvedSymbolTarget& rhs) const {
224 return (raw == rhs.raw);
225 }
226 bool operator!=(const ResolvedSymbolTarget& rhs) const {
227 return (raw != rhs.raw);
228 }
229 };
230 static_assert(sizeof(ResolvedSymbolTarget) == 8);
231
232
233 // ObjC optimisations
234 struct ObjCImageOffset {
235 union {
236 uint32_t raw = 0;
237 struct {
238 uint32_t imageIndex : 8;
239 uint32_t imageOffset : 24;
240 };
241 };
242
243 enum : uint32_t {
244 // The unused value so that we have a sentinel in our hash table
245 sentinelValue = 0xFFFFFFFF,
246
247 // The maximum image index
248 maximumImageIndex = (1U << 8) - 1,
249
250 // The maximum offset from the start of the strings section
251 maximumOffset = (1U << 24) - 1
252 };
253 };
254
255 struct ObjCClassNameImageOffset {
256 union {
257 uint32_t raw = 0;
258 struct {
259 uint32_t classNameImageIndex : 8;
260 uint32_t classNameImageOffset : 24;
261 };
262 };
263
264 enum : uint32_t {
265 // The unused value so that we have a sentinel in our hash table
266 sentinelValue = 0xFFFFFFFF,
267
268 // The maximum image index
269 maximumImageIndex = (1U << 8) - 1,
270
271 // The maximum offset from the start of the strings section
272 maximumOffset = (1U << 24) - 1
273 };
274 };
275
276 struct ObjCClassImageOffset {
277 union {
278 uint32_t raw = 0;
279 struct {
280 uint32_t imageIndex : 8;
281 uint32_t imageOffset : 23;
282 uint32_t isDuplicate : 1; // == 0
283 } classData;
284 struct {
285 uint32_t count : 8;
286 uint32_t index : 23;
287 uint32_t isDuplicate : 1; // == 1
288 } duplicateData;
289 };
290
291 enum : uint32_t {
292 // The unused value so that we have a sentinel in our hash table
293 sentinelValue = 0xFFFFFFFF,
294
295 // The maximum image index
296 maximumImageIndex = (1U << 8) - 1,
297
298 // The maximum offset from the start of the class data section
299 maximumOffset = (1U << 23) - 1
300 };
301 };
302
303 static_assert(sizeof(ObjCClassImageOffset) == 4, "Invalid size");
304
305 static_assert(ObjCClassNameImageOffset::maximumImageIndex == ObjCClassImageOffset::maximumImageIndex , "Invalid indices");
306
307 struct ObjCDuplicateClass {
308 union {
309 uint32_t raw = 0;
310 struct {
311 uint32_t sharedCacheClassOptIndex : 20;
312 uint32_t sharedCacheClassDuplicateIndex : 12;
313 };
314 };
315
316 enum : uint32_t {
317 // The unused value so that we have a sentinel in our hash table
318 sentinelValue = 0xFFFFFFFF
319 };
320 };
321
322 static_assert(sizeof(ObjCDuplicateClass) == 4, "Invalid size");
323
324 struct ObjCSelectorImage {
325 ImageNum imageNum;
326 uint32_t offset;
327 };
328
329 struct ObjCClassImage {
330 ImageNum imageNum;
331 uint32_t offsetOfClassNames;
332 uint32_t offsetOfClasses;
333 };
334
335 typedef MachOLoaded::ChainedFixupPointerOnDisk ChainedFixupPointerOnDisk;
336
337 // the following are only valid if inDyldCache() returns true
338 uint32_t cacheOffset() const;
339 uint32_t patchStartIndex() const;
340 uint32_t patchCount() const;
341 void forEachCacheSegment(void (^handler)(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const;
342
343
344 // the following are only valid if inDyldCache() returns false
345 uint64_t vmSizeToMap() const;
346 uint64_t sliceOffsetInFile() const;
347 bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const;
348 bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const;
349 void forEachDiskSegment(void (^handler)(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize,
350 uint8_t permissions, bool laterReadOnly, bool& stop)) const;
351 void forEachFixup(void (^rebase)(uint64_t imageOffsetToRebase, bool& stop),
352 void (^bind)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
353 void (^chainedFixups)(uint64_t imageOffsetToStarts, const Array<ResolvedSymbolTarget>& targets, bool& stop),
354 void (^fixupObjCImageInfo)(uint64_t imageOffsetToFixup),
355 void (^fixupObjCProtocol)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
356 void (^fixupObjCSelRef)(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool& stop),
357 void (^fixupObjCStableSwift)(uint64_t imageOffsetToFixup, bool& stop),
358 void (^fixupObjCMethodList)(uint64_t imageOffsetToFixup, bool& stop)) const;
359 void forEachTextReloc(void (^rebase)(uint32_t imageOffsetToRebase, bool& stop),
360 void (^bind)(uint32_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop)) const;
361
362 static_assert(sizeof(ResolvedSymbolTarget) == 8, "Overflow in size of SymbolTargetLocation");
363
364 static uint32_t hashFunction(const char*);
365
366 private:
367 friend struct Closure;
368 friend class ImageWriter;
369 friend class ClosureBuilder;
370 friend class ClosureWriter;
371 friend class LaunchClosureWriter;
372
373 uint32_t pageSize() const;
374
375 struct Flags
376 {
377 uint64_t imageNum : 16,
378 maxLoadCount : 12,
379 isInvalid : 1, // an error occurred creating the info for this image
380 has16KBpages : 1,
381 is64 : 1,
382 hasObjC : 1,
383 mayHavePlusLoads : 1,
384 isEncrypted : 1, // image is DSMOS or FairPlay encrypted
385 hasWeakDefs : 1,
386 neverUnload : 1,
387 cwdSameAsThis : 1, // dylibs use file system relative paths, cwd must be main's dir
388 isPlatformBinary : 1, // part of OS - can be loaded into LV process
389 isBundle : 1,
390 isDylib : 1,
391 isExecutable : 1,
392 overridableDylib : 1, // only applicable to cached dylibs
393 inDyldCache : 1,
394 hasTerminators : 1,
395 hasReadOnlyData : 1,
396 hasChainedFixups : 1,
397 hasPrecomputedObjC : 1,
398 padding : 17;
399 };
400
401 static_assert(sizeof(Flags) == sizeof(uint64_t), "Flags overflow");
402
403 const Flags& getFlags() const;
404
405 struct PathAndHash
406 {
407 uint32_t hash;
408 char path[];
409 };
410
411 // In disk based images, all segments are multiples of page size
412 // This struct just tracks the size (disk and vm) of each segment.
413 // This is compact for most every image which have contiguous segments.
414 // If the image does not have contiguous segments (rare), an extra
415 // DiskSegment is inserted with the paddingNotSeg bit set.
416 struct DiskSegment
417 {
418 uint64_t filePageCount : 30,
419 vmPageCount : 30,
420 permissions : 3,
421 paddingNotSeg : 1;
422
423 // We only have three bits for permissions, and need a way to
424 // encode segments that are initially r/w then made read-only
425 // after fixups are done. Previously, the only valid patterns
426 // were: ---, r--, rw-, r-x. We now add -w- to mean r/w -> r/o.
427 enum { kReadOnlyDataPermissions = VM_PROT_WRITE };
428 };
429
430
431 // In cache DATA_DIRTY is not page aligned or sized
432 // This struct allows segments with any alignment and up to 256MB in size
433 struct DyldCacheSegment
434 {
435 uint64_t cacheOffset : 32,
436 size : 28,
437 permissions : 4;
438 };
439
440 struct CodeSignatureLocation
441 {
442 uint32_t fileOffset;
443 uint32_t fileSize;
444 };
445
446 struct FileInfo
447 {
448 uint64_t inode;
449 uint64_t modTime;
450 };
451
452 struct FairPlayRange
453 {
454 uint32_t rangeStart; // The byte offset of the start of the range.
455 uint32_t rangeLength; // How long is the fairplay range in bytes
456 };
457
458 struct MappingInfo
459 {
460 uint32_t totalVmPages;
461 uint32_t sliceOffsetIn4K;
462 };
463
464 struct InitializerSectionRange
465 {
466 uint32_t sectionOffset;
467 uint32_t sectionSize;
468 };
469
470 struct LinkedImage {
471
472 LinkedImage() : imgNum(0), linkKind(0) {
473 }
474 LinkedImage(LinkKind k, ImageNum num) : imgNum(num), linkKind((uint32_t)k) {
475 assert((num & 0xC0000000) == 0);
476 }
477
478 LinkKind kind() const { return (LinkKind)linkKind; }
479 ImageNum imageNum() const { return imgNum; }
480 void clearKind() { linkKind = 0; }
481
482 bool operator==(const LinkedImage& rhs) const {
483 return (linkKind == rhs.linkKind) && (imgNum == rhs.imgNum);
484 }
485 bool operator!=(const LinkedImage& rhs) const {
486 return (linkKind != rhs.linkKind) || (imgNum != rhs.imgNum);
487 }
488 private:
489 uint32_t imgNum : 30,
490 linkKind : 2; // LinkKind
491 };
492
493 const Array<LinkedImage> dependentsArray() const;
494
495 struct RebasePattern
496 {
497 uint32_t repeatCount : 20,
498 contigCount : 8, // how many contiguous pointers neeed rebasing
499 skipCount : 4; // how many pointers to skip between contig groups
500 // If contigCount == 0, then there are no rebases for this entry,
501 // instead it advances the rebase location by repeatCount*skipCount.
502 // If all fields are zero, then the rebase position is reset to the start.
503 // This is to support old binaries with some non-monotonically-increasing rebases.
504 };
505 const Array<RebasePattern> rebaseFixups() const;
506
507 struct BindPattern
508 {
509 Image::ResolvedSymbolTarget target;
510 uint64_t startVmOffset : 40, // max 1TB offset
511 skipCount : 8,
512 repeatCount : 16;
513 };
514 const Array<BindPattern> bindFixups() const;
515
516 // An optimzied selector reference bind will either point to the shared cache
517 // or a binary optimized in our launch closure. We can use the index in to each
518 // of their respective selector hash tables as the target or the bind.
519 union SelectorReferenceFixup
520 {
521 uint32_t chainStartVMOffset;
522 struct {
523 uint32_t index : 24, // max 16m entries in the table
524 next : 7, // (next * 4) -> offset to next fixup
525 inSharedCache : 1; // 0 -> in the closure. 1 -> in the cache
526 } chainEntry;
527 };
528
529 struct ProtocolISAFixup
530 {
531 uint64_t startVmOffset : 40, // max 1TB offset
532 skipCount : 8,
533 repeatCount : 16;
534 };
535
536 struct ClassStableSwiftFixup
537 {
538 uint64_t startVmOffset : 40, // max 1TB offset
539 skipCount : 8,
540 repeatCount : 16;
541 };
542
543 struct MethodListFixup
544 {
545 uint64_t startVmOffset : 40, // max 1TB offset
546 skipCount : 8,
547 repeatCount : 16;
548 };
549
550 void objcFixups(ResolvedSymbolTarget& objcProtocolClassTarget,
551 uint64_t& objcImageInfoVMOffset,
552 Array<ProtocolISAFixup>& protocolISAFixups,
553 Array<SelectorReferenceFixup>& selRefFixups,
554 Array<ClassStableSwiftFixup>& classStableSwiftFixups,
555 Array<MethodListFixup>& methodListFixups) const;
556
557 struct TextFixupPattern
558 {
559 Image::ResolvedSymbolTarget target;
560 uint32_t startVmOffset;
561 uint16_t repeatCount;
562 uint16_t skipCount;
563 };
564 const Array<TextFixupPattern> textFixups() const;
565
566 // for use with chained fixups
567 uint64_t chainedStartsOffset() const;
568 const Array<Image::ResolvedSymbolTarget> chainedTargets() const;
569
570 };
571
572 /*
573 Dyld cache patching notes:
574
575 The dyld cache needs to be patched to support interposing and dylib "roots".
576
577 For cached dylibs overrides:
578 Closure build time:
579 1) LoadedImages will contain the new dylib, so all symbol look ups
580 will naturally find new impl. Only dyld cache needs special help.
581 2) LoadedImages entry will have flag for images that override cache.
582 3) When setting Closure attributes, if flag is set, builder will
583 iterate PatchableExport entries in Image* from cache and create
584 a PatchEntry for each.
585 Runtime:
586 1) [lib]dyld will iterate PatchEntry in closure and patch cache
587
588 For interposing:
589 Closure build time:
590 1) After Images built, if __interpose section(s) exist, builder will
591 build InterposingTuple entries for closure
592 2) For being-built closure and launch closure, apply any InterposingTuple
593 to modify Image fixups before Image finalized.
594 3) Builder will find PatchableExport entry that matchs stock Impl
595 and add PatchEntry to closure for it.
596 Runtime:
597 1) When closure is loaded (launch or dlopen) PatchEntries are
598 applied (exactly once) to whole cache.
599 2) For each DlopenClosure loaded, any InterposeTuples in *launch* closure
600 are applied to all new images in new DlopenClosure.
601
602 For weak-def coalesing:
603 Closure build time:
604 1) weak_bind entries are turned into -3 ordinal lookup which search through images
605 in load order for first def (like flat). This fixups up all images not in cache.
606 2) When processing -3 ordinals, it continues past first found and if any images
607 past it are in dyld cache and export that same symbol, a PatchEntry is added to
608 closure to fix up all cached uses of that symbol.
609 3) If a weak_bind has strong bit set (no fixup, just def), all images from the dyld
610 cache are checked to see if the export that symbol, if so, a PatchEntry is added
611 to the closure.
612 Runtime:
613 1) When closure is loaded (launch or dlopen) PatchEntries are
614 applied (exactly once) to whole cache.
615
616 */
617
618
619 //
620 // An array (accessible by index) list of Images
621 //
622 struct VIS_HIDDEN ImageArray : public TypedBytes
623 {
624 size_t size() const;
625 size_t startImageNum() const;
626 uint32_t imageCount() const;
627 void forEachImage(void (^callback)(const Image* image, bool& stop)) const;
628 bool hasPath(const char* path, ImageNum& num) const;
629 const Image* imageForNum(ImageNum) const;
630 void deallocate() const;
631
632 static const Image* findImage(const Array<const ImageArray*> imagesArrays, ImageNum imageNum);
633
634 private:
635 friend class ImageArrayWriter;
636
637 uint32_t firstImageNum;
638 uint32_t count : 31;
639 uint32_t hasRoots : 1; // True if this ImageArray contains roots with imageNum's below firstImageNum
640 uint32_t offsets[];
641 // Image data
642 };
643
644
645 struct InterposingTuple
646 {
647 Image::ResolvedSymbolTarget stockImplementation;
648 Image::ResolvedSymbolTarget newImplementation;
649 };
650
651
652 //
653 // Describes how dyld should load a set of mach-o files
654 //
655 struct VIS_HIDDEN Closure : public ContainerTypedBytes
656 {
657 size_t size() const;
658 const ImageArray* images() const;
659 ImageNum topImage() const;
660 void deallocate() const;
661
662 friend class ClosureWriter;
663
664 struct PatchEntry
665 {
666 ImageNum overriddenDylibInCache;
667 uint32_t exportCacheOffset;
668 Image::ResolvedSymbolTarget replacement;
669 };
670
671 struct Warning
672 {
673 enum Type : uint32_t {
674 duplicateObjCClass = 0
675 };
676
677 Type type;
678 char message[];
679 };
680
681 void forEachPatchEntry(void (^handler)(const PatchEntry& entry)) const;
682 void forEachWarning(Warning::Type type, void (^handler)(const char* warning, bool& stop)) const;
683 };
684
685
686 //
687 // Describes how dyld should launch a main executable
688 //
689 struct VIS_HIDDEN LaunchClosure : public Closure
690 {
691 // Represents a file on disk we tried to load but skipped as it wasn't valid for our use
692 struct SkippedFile
693 {
694 const char* path;
695 uint64_t inode;
696 uint64_t mtime;
697 };
698
699 bool builtAgainstDyldCache(uuid_t cacheUUID) const;
700 const char* bootUUID() const;
701 void forEachMustBeMissingFile(void (^handler)(const char* path, bool& stop)) const;
702 void forEachSkipIfExistsFile(void (^handler)(const SkippedFile& file, bool& stop)) const;
703 void forEachEnvVar(void (^handler)(const char* keyEqualValue, bool& stop)) const;
704 ImageNum libSystemImageNum() const;
705 void libDyldEntry(Image::ResolvedSymbolTarget& loc) const;
706 bool mainEntry(Image::ResolvedSymbolTarget& mainLoc) const;
707 bool startEntry(Image::ResolvedSymbolTarget& startLoc) const;
708 uint32_t initialLoadCount() const;
709 void forEachInterposingTuple(void (^handler)(const InterposingTuple& tuple, bool& stop)) const;
710 bool usedAtPaths() const;
711 bool usedFallbackPaths() const;
712 bool selectorHashTable(Array<Image::ObjCSelectorImage>& imageNums,
713 const ObjCSelectorOpt*& hashTable) const;
714 bool classAndProtocolHashTables(Array<Image::ObjCClassImage>& imageNums,
715 const ObjCClassOpt*& classHashTable,
716 const ObjCClassOpt*& protocolHashTable) const;
717 void duplicateClassesHashTable(const ObjCClassDuplicatesOpt*& duplicateClassesHashTable) const;
718 bool hasInsertedLibraries() const;
719 bool hasInterposings() const;
720
721 static bool buildClosureCachePath(const char* mainExecutablePath, char closurePath[], const char* tempDir,
722 bool makeDirsIfMissing);
723
724 private:
725 friend class LaunchClosureWriter;
726
727 struct Flags
728 {
729 uint32_t usedAtPaths : 1,
730 usedFallbackPaths : 1,
731 initImageCount : 16,
732 hasInsertedLibraries : 1,
733 padding : 13;
734 };
735 const Flags& getFlags() const;
736 };
737
738
739
740 //
741 // Describes how dyld should dlopen() a mach-o file
742 //
743 struct VIS_HIDDEN DlopenClosure : public Closure
744 {
745
746 };
747
748 // Precomputed perfect hash table of strings.
749 // Base class for closure precomputed selector table and class table.
750 class VIS_HIDDEN ObjCStringTable {
751 public:
752 typedef uint32_t StringTarget;
753
754 private:
755 typedef uint8_t StringHashCheckByte;
756
757 protected:
758
759 uint32_t capacity;
760 uint32_t occupied;
761 uint32_t shift;
762 uint32_t mask;
763 StringTarget sentinelTarget;
764 uint32_t roundedTabSize;
765 uint64_t salt;
766
767 uint32_t scramble[256];
768 uint8_t tab[0]; /* tab[mask+1] (always power-of-2). Rounded up to roundedTabSize */
769 // uint8_t checkbytes[capacity]; /* check byte for each string */
770 // int32_t offsets[capacity]; /* offsets from &capacity to cstrings */
771
772 StringHashCheckByte* checkBytesOffset() {
773 return &tab[roundedTabSize];
774 }
775
776 const StringHashCheckByte* checkBytesOffset() const {
777 return &tab[roundedTabSize];
778 }
779
780 StringTarget* targetsOffset() {
781 return (StringTarget*)(checkBytesOffset() + capacity);
782 }
783
784 const StringTarget* targetsOffset() const {
785 return (StringTarget*)(checkBytesOffset() + capacity);
786 }
787
788 dyld3::Array<StringHashCheckByte> checkBytes() {
789 return dyld3::Array<StringHashCheckByte>((StringHashCheckByte *)checkBytesOffset(), capacity, capacity);
790 }
791 const dyld3::Array<StringHashCheckByte> checkBytes() const {
792 return dyld3::Array<StringHashCheckByte>((StringHashCheckByte *)checkBytesOffset(), capacity, capacity);
793 }
794
795 dyld3::Array<StringTarget> targets() {
796 return dyld3::Array<StringTarget>((StringTarget *)targetsOffset(), capacity, capacity);
797 }
798 const dyld3::Array<StringTarget> targets() const {
799 return dyld3::Array<StringTarget>((StringTarget *)targetsOffset(), capacity, capacity);
800 }
801
802 uint32_t hash(const char *key, size_t keylen) const;
803
804 uint32_t hash(const char *key) const
805 {
806 return hash(key, strlen(key));
807 }
808
809 // The check bytes areused to reject strings that aren't in the table
810 // without paging in the table's cstring data. This checkbyte calculation
811 // catches 4785/4815 rejects when launching Safari; a perfect checkbyte
812 // would catch 4796/4815.
813 StringHashCheckByte checkbyte(const char *key, size_t keylen) const
814 {
815 return ((key[0] & 0x7) << 5) | ((uint8_t)keylen & 0x1f);
816 }
817
818 StringHashCheckByte checkbyte(const char *key) const
819 {
820 return checkbyte(key, strlen(key));
821 }
822
823 StringTarget getPotentialTarget(const char *key) const
824 {
825 uint32_t index = getIndex(key);
826 if (index == indexNotFound)
827 return sentinelTarget;
828 return targets()[index];
829
830 }
831
832 public:
833
834 enum : uint32_t {
835 indexNotFound = ~0U
836 };
837
838 uint32_t getIndex(const char *key) const
839 {
840 size_t keylen = strlen(key);
841 uint32_t h = hash(key, keylen);
842
843 // Use check byte to reject without paging in the table's cstrings
844 StringHashCheckByte h_check = checkBytes()[h];
845 StringHashCheckByte key_check = checkbyte(key, keylen);
846 if (h_check != key_check)
847 return indexNotFound;
848 return h;
849 }
850
851 template<typename PerfectHashT>
852 static size_t size(const PerfectHashT& phash) {
853 // Round tab[] to at least 4 in length to ensure the uint32_t's after are aligned
854 uint32_t roundedTabSize = std::max(phash.mask+1, 4U);
855 size_t tableSize = 0;
856 tableSize += sizeof(ObjCStringTable);
857 tableSize += roundedTabSize;
858 tableSize += phash.capacity * sizeof(StringHashCheckByte);
859 tableSize += phash.capacity * sizeof(StringTarget);
860 return tableSize;
861 }
862
863 // Get a string if it has an entry in the table
864 const char* getString(const char* selName, const Array<uintptr_t>& baseAddresses) const;
865
866 void forEachString(const Array<Image::ObjCSelectorImage>& selectorImages,
867 void (^callback)(uint64_t selVMOffset, ImageNum imageNum)) const;
868
869 template<typename PerfectHashT, typename ImageOffsetT>
870 void write(const PerfectHashT& phash, const Array<std::pair<const char*, ImageOffsetT>>& strings);
871 };
872
873 class VIS_HIDDEN ObjCSelectorOpt : public ObjCStringTable {
874 public:
875 // Get a string if it has an entry in the table
876 // Returns true if an entry is found and sets the imageNum and vmOffset.
877 bool getStringLocation(uint32_t index, const Array<closure::Image::ObjCSelectorImage>& selImages,
878 ImageNum& imageNum, uint64_t& vmOffset) const;
879
880 void forEachString(const Array<Image::ObjCSelectorImage>& selectorImages,
881 void (^callback)(uint64_t selVMOffset, ImageNum imageNum)) const;
882 };
883
884 class VIS_HIDDEN ObjCClassOpt : public ObjCStringTable {
885 private:
886 // ...ObjCStringTable fields...
887 // ClassTarget classOffsets[capacity]; /* offsets from &capacity to class_t and header_info */
888 // DuplicateCount duplicateCount;
889 // ClassTarget duplicateOffsets[duplicatedClasses];
890
891 typedef uint32_t DuplicateCount;
892 typedef Image::ObjCClassImageOffset ClassTarget;
893
894 ClassTarget *classOffsetsStart() { return (ClassTarget *)&targetsOffset()[capacity]; }
895 const ClassTarget *classOffsetsStart() const { return (const ClassTarget *)&targetsOffset()[capacity]; }
896
897 dyld3::Array<ClassTarget> classOffsets() {
898 return dyld3::Array<ClassTarget>((ClassTarget *)classOffsetsStart(), capacity, capacity);
899 }
900 const dyld3::Array<ClassTarget> classOffsets() const {
901 return dyld3::Array<ClassTarget>((ClassTarget *)classOffsetsStart(), capacity, capacity);
902 }
903
904 DuplicateCount& duplicateCount() { return *(DuplicateCount *)&classOffsetsStart()[capacity]; }
905 const DuplicateCount& duplicateCount() const { return *(const DuplicateCount *)&classOffsetsStart()[capacity]; }
906
907 ClassTarget *duplicateOffsetsStart() { return (ClassTarget *)(&duplicateCount()+1); }
908 const ClassTarget *duplicateOffsetsStart() const { return (const ClassTarget *)(&duplicateCount()+1); }
909
910 dyld3::Array<ClassTarget> duplicateOffsets(uint32_t preCalculatedDuplicateCount) {
911 return dyld3::Array<ClassTarget>((ClassTarget *)duplicateOffsetsStart(), preCalculatedDuplicateCount, duplicateCount());
912 }
913 const dyld3::Array<ClassTarget> duplicateOffsets(uint32_t preCalculatedDuplicateCount) const {
914 return dyld3::Array<ClassTarget>((ClassTarget *)duplicateOffsetsStart(), preCalculatedDuplicateCount, duplicateCount());
915 }
916
917 public:
918
919 template<typename PerfectHashT>
920 static size_t size(PerfectHashT& phash, uint32_t duplicateCount)
921 {
922 size_t tableSize = 0;
923 tableSize += ObjCStringTable::size(phash);
924 tableSize += phash.capacity * sizeof(ClassTarget);
925 tableSize += sizeof(DuplicateCount);
926 tableSize += duplicateCount * sizeof(ClassTarget);
927 return tableSize;
928 }
929
930 void forEachClass(const char* className,
931 const Array<std::pair<uintptr_t, uintptr_t>>& nameAndDataBaseAddresses,
932 void (^callback)(void* classPtr, bool isLoaded, bool* stop)) const;
933
934 void forEachClass(const Array<Image::ObjCClassImage>& classImages,
935 void (^nameCallback)(uint64_t classNameVMOffset, ImageNum imageNum),
936 void (^implCallback)(uint64_t classVMOffset, ImageNum imageNum)) const;
937
938 template<typename PerfectHashT, typename ImageOffsetT, typename ClassesMapT>
939 void write(const PerfectHashT& phash, const Array<std::pair<const char*, ImageOffsetT>>& strings,
940 const ClassesMapT& classes, uint32_t preCalculatedDuplicateCount);
941 };
942
943 class VIS_HIDDEN ObjCClassDuplicatesOpt : public ObjCStringTable {
944 public:
945 // Get a class if it has an entry in the table
946 bool getClassLocation(const char* className, const objc_opt::objc_opt_t* objCOpt, void*& classImpl) const;
947
948 void forEachClass(void (^callback)(Image::ObjCDuplicateClass duplicateClass)) const;
949 };
950
951 } // namespace closure
952 } // namespace dyld3
953
954
955 #endif // Closures_h
956
957