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