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