]> git.saurik.com Git - apple/dyld.git/blob - dyld3/Closure.cpp
dyld-851.27.tar.gz
[apple/dyld.git] / dyld3 / Closure.cpp
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 #include <stdint.h>
26 #include <assert.h>
27 #include <uuid/uuid.h>
28 #include <unistd.h>
29 #include <limits.h>
30 #include <mach-o/dyld_priv.h>
31 #include <sys/stat.h>
32 #include <sys/sysctl.h>
33 #include <System/machine/cpu_capabilities.h>
34 #include <_simple.h>
35
36 extern "C" {
37 #include <corecrypto/ccdigest.h>
38 #include <corecrypto/ccsha2.h>
39 }
40
41 #include "Closure.h"
42 #include "MachOFile.h"
43 #include "MachOLoaded.h"
44 #include "StringUtils.h"
45
46 #include "objc-shared-cache.h"
47
48
49 namespace dyld3 {
50 namespace closure {
51
52
53 //////////////////////////// TypedBytes ////////////////////////////////////////
54
55 const void* TypedBytes::payload() const
56 {
57 return (uint8_t*)this + sizeof(TypedBytes);
58 }
59
60 void* TypedBytes::payload()
61 {
62 return (uint8_t*)this + sizeof(TypedBytes);
63 }
64
65
66 //////////////////////////// ContainerTypedBytes ////////////////////////////////////////
67
68 const TypedBytes* ContainerTypedBytes::first() const
69 {
70 return (TypedBytes*)payload();
71 }
72
73 const TypedBytes* ContainerTypedBytes::next(const TypedBytes* p) const
74 {
75 assert((p->payloadLength & 0x3) == 0);
76 return (TypedBytes*)((uint8_t*)(p->payload()) + p->payloadLength);
77 }
78
79 void ContainerTypedBytes::forEachAttribute(void (^handler)(const TypedBytes* typedBytes, bool& stop)) const
80 {
81 assert(((long)this & 0x3) == 0);
82 const TypedBytes* end = next(this);
83 bool stop = false;
84 for (const TypedBytes* p = first(); p < end && !stop; p = next(p)) {
85 handler(p, stop);
86 }
87 }
88
89 void ContainerTypedBytes::forEachAttributePayload(Type requestedType, void (^handler)(const void* payload, uint32_t size, bool& stop)) const
90 {
91 forEachAttribute(^(const TypedBytes* typedBytes, bool& stop) {
92 if ( (Type)(typedBytes->type) != requestedType )
93 return;
94 handler(typedBytes->payload(), typedBytes->payloadLength, stop);
95 });
96 }
97
98 const void* ContainerTypedBytes::findAttributePayload(Type requestedType, uint32_t* payloadSize) const
99 {
100 assert(((long)this & 0x3) == 0);
101 if ( payloadSize != nullptr )
102 *payloadSize = 0;
103 const TypedBytes* end = next(this);
104 bool stop = false;
105 for (const TypedBytes* p = first(); p < end && !stop; p = next(p)) {
106 if ( (Type)(p->type) == requestedType ) {
107 if ( payloadSize != nullptr )
108 *payloadSize = p->payloadLength;
109 return p->payload();
110 }
111 }
112 return nullptr;
113 }
114
115
116 //////////////////////////// Image ////////////////////////////////////////
117
118 const Image::Flags& Image::getFlags() const
119 {
120 return *(Flags*)((uint8_t*)this + 2*sizeof(TypedBytes));
121 }
122
123 bool Image::isInvalid() const
124 {
125 return getFlags().isInvalid;
126 }
127
128 size_t Image::size() const
129 {
130 return sizeof(TypedBytes) + this->payloadLength;
131 }
132
133 ImageNum Image::imageNum() const
134 {
135 return getFlags().imageNum;
136 }
137
138 // returns true iff 'num' is this image's ImageNum, or this image overrides that imageNum (in dyld cache)
139 bool Image::representsImageNum(ImageNum num) const
140 {
141 const Flags& flags = getFlags();
142 if ( flags.imageNum == num )
143 return true;
144 if ( !flags.isDylib )
145 return false;
146 if ( !flags.hasOverrideImageNum )
147 return false;
148 ImageNum cacheImageNum;
149 if ( isOverrideOfDyldCacheImage(cacheImageNum) )
150 return (cacheImageNum == num);
151 return false;
152 }
153
154 uint32_t Image::maxLoadCount() const
155 {
156 return getFlags().maxLoadCount;
157 }
158
159 bool Image::isBundle() const
160 {
161 return getFlags().isBundle;
162 }
163
164 bool Image::isDylib() const
165 {
166 return getFlags().isDylib;
167 }
168
169 bool Image::isExecutable() const
170 {
171 return getFlags().isExecutable;
172 }
173
174 bool Image::hasObjC() const
175 {
176 return getFlags().hasObjC;
177 }
178
179 bool Image::is64() const
180 {
181 return getFlags().is64;
182 }
183
184 bool Image::hasWeakDefs() const
185 {
186 return getFlags().hasWeakDefs;
187 }
188
189 bool Image::mayHavePlusLoads() const
190 {
191 return getFlags().mayHavePlusLoads;
192 }
193
194 bool Image::neverUnload() const
195 {
196 return getFlags().neverUnload;
197 }
198
199 bool Image::overridableDylib() const
200 {
201 return getFlags().overridableDylib;
202 }
203
204 bool Image::inDyldCache() const
205 {
206 return getFlags().inDyldCache;
207 }
208
209 const char* Image::path() const
210 {
211 // might be multiple pathWithHash enties, first is canonical name
212 const PathAndHash* result = (PathAndHash*)findAttributePayload(Type::pathWithHash);
213 assert(result && "Image missing pathWithHash");
214 return result->path;
215 }
216
217 const char* Image::leafName() const
218 {
219 uint32_t size;
220 // might be multiple pathWithHash enties, first is canonical name
221 const PathAndHash* result = (PathAndHash*)findAttributePayload(Type::pathWithHash, &size);
222 assert(result && "Image missing pathWithHash");
223 for (const char* p=(char*)result + size; p > result->path; --p) {
224 if ( *p == '/' )
225 return p+1;
226 }
227 return result->path;
228 }
229
230 bool Image::hasFileModTimeAndInode(uint64_t& inode, uint64_t& mTime) const
231 {
232 uint32_t size;
233 const FileInfo* info = (FileInfo*)(findAttributePayload(Type::fileInodeAndTime, &size));
234 if ( info != nullptr ) {
235 assert(size == sizeof(FileInfo));
236 inode = info->inode;
237 mTime = info->modTime;
238 return true;
239 }
240 return false;
241 }
242
243 void Image::forEachCDHash(void (^handler)(const uint8_t cdHash[20], bool& stop)) const
244 {
245 forEachAttribute(^(const TypedBytes* typedBytes, bool& stopLoop) {
246 if ( (Type)(typedBytes->type) != Type::cdHash )
247 return;
248 assert(typedBytes->payloadLength == 20);
249 const uint8_t* bytes = (const uint8_t*)typedBytes->payload();
250 handler(bytes, stopLoop);
251 });
252 }
253
254 bool Image::getUuid(uuid_t uuid) const
255 {
256 uint32_t size;
257 const uint8_t* bytes = (uint8_t*)(findAttributePayload(Type::uuid, &size));
258 if ( bytes == nullptr )
259 return false;
260 assert(size == 16);
261 memcpy(uuid, bytes, 16);
262 return true;
263 }
264
265 bool Image::hasCodeSignature(uint32_t& sigFileOffset, uint32_t& sigSize) const
266 {
267 uint32_t sz;
268 const Image::CodeSignatureLocation* sigInfo = (Image::CodeSignatureLocation*)(findAttributePayload(Type::codeSignLoc, &sz));
269 if ( sigInfo != nullptr ) {
270 assert(sz == sizeof(Image::CodeSignatureLocation));
271 sigFileOffset = sigInfo->fileOffset;
272 sigSize = sigInfo->fileSize;
273 return true;
274 }
275 return false;
276 }
277
278 bool Image::isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const
279 {
280 uint32_t sz;
281 const Image::FairPlayRange* fpInfo = (Image::FairPlayRange*)(findAttributePayload(Type::fairPlayLoc, &sz));
282 if ( fpInfo != nullptr ) {
283 assert(sz == sizeof(Image::FairPlayRange));
284 textOffset = fpInfo->rangeStart;
285 size = fpInfo->rangeLength;
286 return true;
287 }
288 return false;
289 }
290
291 const Array<Image::LinkedImage> Image::dependentsArray() const
292 {
293 uint32_t size;
294 LinkedImage* dependents = (LinkedImage*)findAttributePayload(Type::dependents, &size);
295 assert((size % sizeof(LinkedImage)) == 0);
296 uintptr_t count = size / sizeof(LinkedImage);
297 return Array<Image::LinkedImage>(dependents, count, count);
298 }
299
300 void Image::forEachDependentImage(void (^handler)(uint32_t dependentIndex, LinkKind kind, ImageNum imageNum, bool& stop)) const
301 {
302 uint32_t size;
303 const LinkedImage* dependents = (LinkedImage*)findAttributePayload(Type::dependents, &size);
304 assert((size % sizeof(LinkedImage)) == 0);
305 const uint32_t count = size / sizeof(LinkedImage);
306 bool stop = false;
307 for (uint32_t i=0; (i < count) && !stop; ++i) {
308 LinkKind kind = dependents[i].kind();
309 ImageNum imageNum = dependents[i].imageNum();
310 // ignore missing weak links
311 if ( (imageNum == kMissingWeakLinkedImage) && (kind == LinkKind::weak) )
312 continue;
313 handler(i, kind, imageNum, stop);
314 }
315 }
316
317 ImageNum Image::dependentImageNum(uint32_t depIndex) const
318 {
319 uint32_t size;
320 const LinkedImage* dependents = (LinkedImage*)findAttributePayload(Type::dependents, &size);
321 assert((size % sizeof(LinkedImage)) == 0);
322 const uint32_t count = size / sizeof(LinkedImage);
323 assert(depIndex < count);
324 return dependents[depIndex].imageNum();
325 }
326
327
328 uint32_t Image::hashFunction(const char* str)
329 {
330 uint32_t h = 0;
331 for (const char* s=str; *s != '\0'; ++s)
332 h = h*5 + *s;
333 return h;
334 }
335
336 void Image::forEachAlias(void (^handler)(const char* aliasPath, bool& stop)) const
337 {
338 __block bool foundFirst = false;
339 forEachAttribute(^(const TypedBytes* typedBytes, bool& stopLoop) {
340 if ( (Type)(typedBytes->type) != Type::pathWithHash )
341 return;
342 if ( foundFirst ) {
343 const PathAndHash* aliasInfo = (PathAndHash*)typedBytes->payload();
344 handler(aliasInfo->path, stopLoop);
345 }
346 else {
347 foundFirst = true;
348 }
349 });
350 }
351
352 bool Image::hasPathWithHash(const char* path, uint32_t hash) const
353 {
354 __block bool found = false;
355 forEachAttribute(^(const TypedBytes* typedBytes, bool& stop) {
356 if ( (Type)(typedBytes->type) != Type::pathWithHash )
357 return;
358 const PathAndHash* pathInfo = (PathAndHash*)typedBytes->payload();
359 if ( (pathInfo->hash == hash) && (strcmp(path, pathInfo->path) == 0) ) {
360 stop = true;
361 found = true;
362 }
363 });
364 return found;
365 }
366
367 void Image::forEachDiskSegment(void (^handler)(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize,
368 uint8_t permissions, bool laterReadOnly, bool& stop)) const
369 {
370 uint32_t size;
371 const DiskSegment* segments = (DiskSegment*)findAttributePayload(Type::diskSegment, &size);
372 assert(segments != nullptr);
373 assert((size % sizeof(DiskSegment)) == 0);
374 const uint32_t count = size / sizeof(DiskSegment);
375 const uint32_t pageSz = pageSize();
376 uint32_t segIndex = 0;
377 uint32_t fileOffset = 0;
378 int64_t vmOffset = 0;
379 // decrement vmOffset by all segments before TEXT (e.g. PAGEZERO)
380 for (uint32_t i=0; i < count; ++i) {
381 const DiskSegment* seg = &segments[i];
382 if ( seg->filePageCount != 0 ) {
383 break;
384 }
385 vmOffset -= (uint64_t)seg->vmPageCount * pageSz;
386 }
387 // walk each segment and call handler
388 bool stop = false;
389 for (uint32_t i=0; i < count && !stop; ++i) {
390 const DiskSegment* seg = &segments[i];
391 uint64_t vmSize = (uint64_t)seg->vmPageCount * pageSz;
392 uint32_t fileSize = seg->filePageCount * pageSz;
393 if ( !seg->paddingNotSeg ) {
394 uint8_t perms = seg->permissions;
395 bool laterRO = false;
396 // read-only data segments are encoded as .w. , initially make them r/w
397 if ( perms == Image::DiskSegment::kReadOnlyDataPermissions ) {
398 perms = VM_PROT_READ|VM_PROT_WRITE;
399 laterRO = true;
400 }
401 handler(segIndex, ( fileSize == 0) ? 0 : fileOffset, fileSize, vmOffset, vmSize, perms, laterRO, stop);
402 ++segIndex;
403 }
404 vmOffset += vmSize;
405 fileOffset += fileSize;
406 }
407 }
408
409 uint32_t Image::pageSize() const
410 {
411 if ( getFlags().has16KBpages )
412 return 0x4000;
413 else
414 return 0x1000;
415 }
416
417 uint32_t Image::cacheOffset() const
418 {
419 uint32_t size;
420 const DyldCacheSegment* segments = (DyldCacheSegment*)findAttributePayload(Type::cacheSegment, &size);
421 assert(segments != nullptr);
422 assert((size % sizeof(DyldCacheSegment)) == 0);
423 return segments[0].cacheOffset;
424 }
425
426 void Image::forEachCacheSegment(void (^handler)(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const
427 {
428 uint32_t size;
429 const DyldCacheSegment* segments = (DyldCacheSegment*)findAttributePayload(Type::cacheSegment, &size);
430 assert(segments != nullptr);
431 assert((size % sizeof(DyldCacheSegment)) == 0);
432 const uint32_t count = size / sizeof(DyldCacheSegment);
433 bool stop = false;
434 for (uint32_t i=0; i < count; ++i) {
435 uint64_t vmOffset = segments[i].cacheOffset - segments[0].cacheOffset;
436 uint64_t vmSize = segments[i].size;
437 uint8_t permissions = segments[i].permissions;
438 handler(i, vmOffset, vmSize, permissions, stop);
439 if ( stop )
440 break;
441 }
442 }
443
444 uint64_t Image::textSize() const
445 {
446 __block uint64_t result = 0;
447 if ( inDyldCache() ) {
448 forEachCacheSegment(^(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop) {
449 result = vmSize;
450 stop = true;
451 });
452 }
453 else {
454 forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool laterReadOnly, bool& stop) {
455 if ( permissions != 0) {
456 result = vmSize;
457 stop = true;
458 }
459 });
460 }
461 return result;
462 }
463
464 bool Image::containsAddress(const void* addr, const void* imageLoadAddress, uint8_t* permsResult) const
465 {
466 __block bool result = false;
467 uint64_t targetAddr = (uint64_t)addr;
468 uint64_t imageStart = (uint64_t)imageLoadAddress;
469 if ( inDyldCache() ) {
470 forEachCacheSegment(^(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop) {
471 if ( (targetAddr >= imageStart+vmOffset) && (targetAddr < imageStart+vmOffset+vmSize) ) {
472 result = true;
473 if ( permsResult )
474 *permsResult = permissions;
475 stop = true;
476 }
477 });
478 }
479 else {
480 forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool laterReadOnly, bool& stop) {
481 if ( (targetAddr >= imageStart+vmOffset) && (targetAddr < imageStart+vmOffset+vmSize) ) {
482 result = true;
483 if ( permsResult )
484 *permsResult = permissions;
485 stop = true;
486 }
487 });
488 }
489 return result;
490 }
491
492 uint64_t Image::vmSizeToMap() const
493 {
494 uint32_t size;
495 const Image::MappingInfo* info = (Image::MappingInfo*)(findAttributePayload(Type::mappingInfo, &size));
496 assert(info != nullptr);
497 assert(size == sizeof(Image::MappingInfo));
498 return info->totalVmPages * pageSize();
499 }
500
501 uint64_t Image::sliceOffsetInFile() const
502 {
503 uint32_t size;
504 const Image::MappingInfo* info = (Image::MappingInfo*)(findAttributePayload(Type::mappingInfo, &size));
505 assert(info != nullptr);
506 assert(size == sizeof(Image::MappingInfo));
507 return info->sliceOffsetIn4K * 0x1000;
508 }
509
510 void Image::forEachInitializer(const void* imageLoadAddress, void (^handler)(const void* initializer)) const
511 {
512 uint32_t size;
513 const uint32_t* inits = (uint32_t*)findAttributePayload(Type::initOffsets, &size);
514 if ( inits != nullptr ) {
515 assert((size % sizeof(uint32_t)) == 0);
516 const uint32_t count = size / sizeof(uint32_t);
517 for (uint32_t i=0; i < count; ++i) {
518 uint32_t offset = inits[i];
519 const void* init = (void*)((uint8_t*)imageLoadAddress + offset);
520 handler(init);
521 }
522 return;
523 }
524 const Image::InitializerSectionRange* range = (Image::InitializerSectionRange*)findAttributePayload(Type::initsSection, &size);
525 if ( range != nullptr ) {
526 const uint32_t pointerSize = is64() ? 8 : 4;
527 const uint32_t* start32 = (uint32_t*)((uint8_t*)imageLoadAddress + range->sectionOffset);
528 const uint64_t* start64 = (uint64_t*)((uint8_t*)imageLoadAddress + range->sectionOffset);
529 const uint32_t count = range->sectionSize / pointerSize;
530 for (uint32_t i=0; i < count; ++i) {
531 if ( pointerSize == 8 )
532 handler((void*)(long)(start64[i]));
533 else
534 handler((void*)(long)(start32[i]));
535 }
536 }
537 }
538
539 bool Image::forEachInitializerSection(void (^handler)(uint32_t sectionOffset, uint32_t sectionSize)) const
540 {
541 __block bool result = false;
542 forEachAttributePayload(Type::initsSection, ^(const void* payload, uint32_t size, bool& stop) {
543 const Image::InitializerSectionRange* range = (Image::InitializerSectionRange*)payload;
544 assert((size % sizeof(Image::InitializerSectionRange)) == 0);
545 handler(range->sectionOffset, range->sectionSize);
546 result = true;
547 });
548 return result;
549 }
550
551 bool Image::hasInitializers() const
552 {
553 uint32_t size;
554 return ( findAttributePayload(Type::initOffsets, &size) != nullptr );
555 }
556
557 bool Image::hasTerminators() const
558 {
559 return getFlags().hasTerminators;
560 }
561
562 bool Image::hasReadOnlyData() const
563 {
564 return getFlags().hasReadOnlyData;
565 }
566
567 bool Image::hasChainedFixups() const
568 {
569 return getFlags().hasChainedFixups;
570 }
571
572 bool Image::hasPrecomputedObjC() const
573 {
574 return getFlags().hasPrecomputedObjC;
575 }
576
577 bool Image::fixupsNotEncoded() const
578 {
579 return getFlags().fixupsNotEncoded;
580 }
581
582 bool Image::rebasesNotEncoded() const
583 {
584 return getFlags().rebasesNotEncoded;
585 }
586
587 void Image::forEachTerminator(const void* imageLoadAddress, void (^handler)(const void* terminator)) const
588 {
589 uint32_t size;
590 const uint32_t* terms = (uint32_t*)findAttributePayload(Type::termOffsets, &size);
591 if ( terms != nullptr ) {
592 assert((size % sizeof(uint32_t)) == 0);
593 const uint32_t count = size / sizeof(uint32_t);
594 for (uint32_t i=0; i < count; ++i) {
595 uint32_t offset = terms[i];
596 const void* term = (void*)((uint8_t*)imageLoadAddress + offset);
597 handler(term);
598 }
599 }
600 }
601
602 void Image::forEachDOF(const void* imageLoadAddress, void (^handler)(const void* dofSection)) const
603 {
604 uint32_t size;
605 const uint32_t* dofs = (uint32_t*)findAttributePayload(Type::dofOffsets, &size);
606 if ( dofs != nullptr ) {
607 assert((size % sizeof(uint32_t)) == 0);
608 const uint32_t count = size / sizeof(uint32_t);
609 for (uint32_t i=0; i < count; ++i) {
610 uint32_t offset = dofs[i];
611 const void* sect = (void*)((uint8_t*)imageLoadAddress + offset);
612 handler(sect);
613 }
614 }
615 }
616
617 void Image::forEachFixup(void (^rebase)(uint64_t imageOffsetToRebase, bool& stop),
618 void (^bind)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
619 void (^chainedFixups)(uint64_t imageOffsetToStarts, const Array<ResolvedSymbolTarget>& targets, bool& stop),
620 void (^fixupObjCImageInfo)(uint64_t imageOffsetToFixup),
621 void (^fixupObjCProtocol)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
622 void (^fixupObjCSelRef)(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool& stop),
623 void (^fixupObjCStableSwift)(uint64_t imageOffsetToFixup, bool& stop),
624 void (^fixupObjCMethodList)(uint64_t imageOffsetToFixup, bool& stop)) const
625 {
626 const uint32_t pointerSize = is64() ? 8 : 4;
627 uint64_t curRebaseOffset = 0;
628 bool stop = false;
629 for (const Image::RebasePattern& rebasePat : rebaseFixups()) {
630 //fprintf(stderr, " repeat=0x%04X, contig=%d, skip=%d\n", rebasePat.repeatCount, rebasePat.contigCount, rebasePat.skipCount);
631 if ( rebasePat.contigCount == 0 ) {
632 // note: contigCount==0 means this just advances location
633 if ( (rebasePat.repeatCount == 0) && (rebasePat.skipCount == 0) ) {
634 // all zeros is special pattern that means reset to rebase offset to zero
635 curRebaseOffset = 0;
636 }
637 else {
638 curRebaseOffset += rebasePat.repeatCount * rebasePat.skipCount;
639 }
640 }
641 else {
642 for (int r=0; r < rebasePat.repeatCount && !stop; ++r) {
643 for (int i=0; i < rebasePat.contigCount && !stop; ++i) {
644 //fprintf(stderr, " 0x%08llX\n", curRebaseOffset);
645 rebase(curRebaseOffset, stop);
646 curRebaseOffset += pointerSize;
647 }
648 curRebaseOffset += pointerSize * rebasePat.skipCount;
649 }
650 }
651 if ( stop )
652 break;
653 }
654 if ( stop )
655 return;
656
657 stop = this->forEachBind(bind);
658 if ( stop )
659 return;
660
661
662 if (hasChainedFixups())
663 chainedFixups(chainedStartsOffset(), chainedTargets(), stop);
664
665 if ( hasPrecomputedObjC() ) {
666 ResolvedSymbolTarget objcProtocolClassTarget;
667 uint64_t objcImageInfoVMOffset = 0;
668 Array<ProtocolISAFixup> protocolISAFixups;
669 Array<Image::SelectorReferenceFixup> selRefFixupEntries;
670 Array<Image::ClassStableSwiftFixup> classStableSwiftFixups;
671 Array<Image::MethodListFixup> methodListFixups;
672 objcFixups(objcProtocolClassTarget, objcImageInfoVMOffset, protocolISAFixups,
673 selRefFixupEntries, classStableSwiftFixups, methodListFixups);
674
675 // Set the objc image info bit to tell libobjc we are optimized
676 fixupObjCImageInfo(objcImageInfoVMOffset);
677
678
679 // First bind all the protocols to the same Protocol class in libobjc
680 for (const Image::ProtocolISAFixup& bindPat : protocolISAFixups) {
681 uint64_t curBindOffset = bindPat.startVmOffset;
682 for (uint16_t i=0; i < bindPat.repeatCount; ++i) {
683 fixupObjCProtocol(curBindOffset, objcProtocolClassTarget, stop);
684 curBindOffset += (pointerSize * (1 + bindPat.skipCount));
685 if ( stop )
686 break;
687 }
688 if ( stop )
689 break;
690 }
691
692 for (uintptr_t i = 0, e = selRefFixupEntries.count(); i != e; ++i) {
693 Image::SelectorReferenceFixup fixupEntry = selRefFixupEntries[i];
694 // Start a new chain
695 uint64_t curFixupOffset = fixupEntry.chainStartVMOffset;
696 // Now walk the chain until we get a 'next' of 0
697 while (i != e) {
698 fixupEntry = selRefFixupEntries[++i];
699 fixupObjCSelRef(curFixupOffset, fixupEntry.chainEntry.index, fixupEntry.chainEntry.inSharedCache, stop);
700 if ( stop )
701 break;
702 if ( fixupEntry.chainEntry.next == 0 )
703 break;
704 curFixupOffset += (4 * fixupEntry.chainEntry.next);
705 }
706 }
707
708 // Set classes to have stable Swift
709 for (const Image::ClassStableSwiftFixup& bindPat : classStableSwiftFixups) {
710 uint64_t curBindOffset = bindPat.startVmOffset;
711 for (uint16_t i=0; i < bindPat.repeatCount; ++i) {
712 fixupObjCStableSwift(curBindOffset, stop);
713 curBindOffset += (pointerSize * (1 + bindPat.skipCount));
714 if ( stop )
715 break;
716 }
717 if ( stop )
718 break;
719 }
720
721 // Set method lists to be fixed up
722 for (const Image::MethodListFixup& bindPat : methodListFixups) {
723 uint64_t curBindOffset = bindPat.startVmOffset;
724 for (uint16_t i=0; i < bindPat.repeatCount; ++i) {
725 fixupObjCMethodList(curBindOffset, stop);
726 curBindOffset += (pointerSize * (1 + bindPat.skipCount));
727 if ( stop )
728 break;
729 }
730 if ( stop )
731 break;
732 }
733 }
734 }
735
736 bool Image::forEachBind(void (^bind)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop)) const
737 {
738 const uint32_t pointerSize = is64() ? 8 : 4;
739 bool stop = false;
740 for (const Image::BindPattern& bindPat : bindFixups()) {
741 uint64_t curBindOffset = bindPat.startVmOffset;
742 for (uint16_t i=0; i < bindPat.repeatCount; ++i) {
743 bind(curBindOffset, bindPat.target, stop);
744 curBindOffset += (pointerSize * (1 + bindPat.skipCount));
745 if ( stop )
746 break;
747 }
748 if ( stop )
749 break;
750 }
751 return stop;
752 }
753
754 void Image::forEachTextReloc(void (^rebase)(uint32_t imageOffsetToRebase, bool& stop),
755 void (^bind)(uint32_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop)) const
756 {
757 bool stop = false;
758 const Array<Image::TextFixupPattern> f = textFixups();
759 for (const Image::TextFixupPattern& pat : f) {
760 uint32_t curOffset = pat.startVmOffset;
761 for (uint16_t i=0; i < pat.repeatCount; ++i) {
762 if ( pat.target.raw == 0 )
763 rebase(curOffset, stop);
764 else
765 bind(curOffset, pat.target, stop);
766 curOffset += pat.skipCount;
767 }
768 }
769 }
770
771 const Array<Image::RebasePattern> Image::rebaseFixups() const
772 {
773 uint32_t rebaseFixupsSize;
774 Image::RebasePattern* rebaseFixupsContent = (RebasePattern*)findAttributePayload(Type::rebaseFixups, &rebaseFixupsSize);
775 uint32_t rebaseCount = rebaseFixupsSize/sizeof(RebasePattern);
776 return Array<RebasePattern>(rebaseFixupsContent, rebaseCount, rebaseCount);
777 }
778
779 const Array<Image::BindPattern> Image::bindFixups() const
780 {
781 uint32_t bindFixupsSize;
782 BindPattern* bindFixupsContent = (BindPattern*)findAttributePayload(Type::bindFixups, &bindFixupsSize);
783 uint32_t bindCount = bindFixupsSize/sizeof(BindPattern);
784 return Array<BindPattern>(bindFixupsContent, bindCount, bindCount);
785 }
786
787 uint64_t Image::chainedStartsOffset() const
788 {
789 uint32_t size;
790 uint64_t* startsOffset = (uint64_t*)findAttributePayload(Type::chainedStartsOffset, &size);
791 if ( startsOffset == nullptr )
792 return 0; // means no pre-computed offset to starts table
793 assert(size == sizeof(uint64_t));
794 return *startsOffset;
795 }
796
797 void Image::objcFixups(ResolvedSymbolTarget& objcProtocolClassTarget,
798 uint64_t& objcImageInfoVMOffset,
799 Array<ProtocolISAFixup>& protocolISAFixups,
800 Array<SelectorReferenceFixup>& selRefFixups,
801 Array<ClassStableSwiftFixup>& classStableSwiftFixups,
802 Array<MethodListFixup>& methodListFixups) const
803 {
804 // The layout here is:
805 // ResolvedSymbolTarget
806 // uint64_t vmOffset to objc_imageinfo
807 // uint32_t protocol count
808 // uint32_t selector reference count
809 // array of ProtocolISAFixup
810 // array of SelectorReferenceFixup
811 // optional uint32_t stable swift fixup count
812 // optional uint32_t method list fixup count
813 // optional array of ClassStableSwiftFixup
814 // optional array of MethodListFixup
815
816 if (!hasPrecomputedObjC())
817 return;
818
819 uint32_t contentSize;
820 const uint8_t* fixupsContent = (uint8_t*)findAttributePayload(Type::objcFixups, &contentSize);
821 const uint8_t* fixupsContentEnd = fixupsContent + contentSize;
822
823 // Get the statically sized data
824 uint32_t protocolFixupCount = 0;
825 uint32_t selRefFixupCount = 0;
826 memcpy(&objcProtocolClassTarget, fixupsContent, sizeof(ResolvedSymbolTarget));
827 fixupsContent += sizeof(ResolvedSymbolTarget);
828 memcpy(&objcImageInfoVMOffset, fixupsContent, sizeof(uint64_t));
829 fixupsContent += sizeof(uint64_t);
830 memcpy(&protocolFixupCount, fixupsContent, sizeof(uint32_t));
831 fixupsContent += sizeof(uint32_t);
832 memcpy(&selRefFixupCount, fixupsContent, sizeof(uint32_t));
833 fixupsContent += sizeof(uint32_t);
834
835 // Get the protocol fixups
836 if ( protocolFixupCount != 0) {
837 protocolISAFixups = Array<ProtocolISAFixup>((ProtocolISAFixup*)fixupsContent, protocolFixupCount, protocolFixupCount);
838 fixupsContent += (sizeof(ProtocolISAFixup) * protocolFixupCount);
839 }
840
841 // Get the selector reference fixups
842 if ( selRefFixupCount != 0) {
843 selRefFixups = Array<SelectorReferenceFixup>((SelectorReferenceFixup*)fixupsContent, selRefFixupCount, selRefFixupCount);
844 fixupsContent += (sizeof(SelectorReferenceFixup) * selRefFixupCount);
845 }
846
847 // Old closures end here, but newer ones might have additional fixups
848 if (fixupsContent == fixupsContentEnd)
849 return;
850
851 uint32_t stableSwiftFixupCount = 0;
852 uint32_t methodListFixupCount = 0;
853 memcpy(&stableSwiftFixupCount, fixupsContent, sizeof(uint32_t));
854 fixupsContent += sizeof(uint32_t);
855 memcpy(&methodListFixupCount, fixupsContent, sizeof(uint32_t));
856 fixupsContent += sizeof(uint32_t);
857
858 // Get the stable swift fixups
859 if ( stableSwiftFixupCount != 0) {
860 classStableSwiftFixups = Array<ClassStableSwiftFixup>((ClassStableSwiftFixup*)fixupsContent, stableSwiftFixupCount, stableSwiftFixupCount);
861 fixupsContent += (sizeof(ClassStableSwiftFixup) * stableSwiftFixupCount);
862 }
863
864 // Get the method list fixups
865 if ( methodListFixupCount != 0) {
866 methodListFixups = Array<MethodListFixup>((MethodListFixup*)fixupsContent, methodListFixupCount, methodListFixupCount);
867 fixupsContent += (sizeof(MethodListFixup) * methodListFixupCount);
868 }
869 }
870
871 const Array<Image::ResolvedSymbolTarget> Image::chainedTargets() const
872 {
873 uint32_t size;
874 ResolvedSymbolTarget* targetsContent = (ResolvedSymbolTarget*)findAttributePayload(Type::chainedFixupsTargets, &size);
875 uint32_t count = size/sizeof(ResolvedSymbolTarget);
876 return Array<ResolvedSymbolTarget>(targetsContent, count, count);
877 }
878
879 const Array<Image::TextFixupPattern> Image::textFixups() const
880 {
881 uint32_t fixupsSize;
882 TextFixupPattern* fixupsContent = (TextFixupPattern*)findAttributePayload(Type::textFixups, &fixupsSize);
883 uint32_t count = fixupsSize/sizeof(TextFixupPattern);
884 return Array<TextFixupPattern>(fixupsContent, count, count);
885 }
886
887 bool Image::isOverrideOfDyldCacheImage(ImageNum& imageNum) const
888 {
889 uint32_t size;
890 const uint32_t* content = (uint32_t*)findAttributePayload(Type::imageOverride, &size);
891 if ( content != nullptr ) {
892 assert(size == sizeof(uint32_t));
893 imageNum = *content;
894 return true;
895 }
896 return false;
897 }
898
899 void Image::forEachImageToInitBefore(void (^handler)(ImageNum imageToInit, bool& stop)) const
900 {
901 uint32_t size;
902 const ImageNum* initBefores = (ImageNum*)findAttributePayload(Type::initBefores, &size);
903 if ( initBefores != nullptr ) {
904 assert((size % sizeof(ImageNum)) == 0);
905 const uint32_t count = size / sizeof(ImageNum);
906 bool stop = false;
907 for (uint32_t i=0; (i < count) && !stop; ++i) {
908 handler(initBefores[i], stop);
909 }
910 }
911 }
912
913 const char* Image::variantString() const
914 {
915 return (this->fixupsNotEncoded() ? "minimal" : "full");
916 }
917
918 //////////////////////////// ImageArray ////////////////////////////////////////
919
920 size_t ImageArray::size() const
921 {
922 return sizeof(TypedBytes) + this->payloadLength;
923 }
924
925 size_t ImageArray::startImageNum() const
926 {
927 return firstImageNum;
928 }
929
930 uint32_t ImageArray::imageCount() const
931 {
932 return count;
933 }
934
935 void ImageArray::forEachImage(void (^callback)(const Image* image, bool& stop)) const
936 {
937 bool stop = false;
938 for (uint32_t i=0; i < count && !stop; ++i) {
939 const Image* image = (Image*)((uint8_t*)payload() + offsets[i]);
940 callback(image, stop);
941 if (stop)
942 break;
943 }
944 }
945
946 bool ImageArray::hasPath(const char* path, ImageNum& num) const
947 {
948 const uint32_t hash = Image::hashFunction(path);
949 __block bool found = false;
950 forEachImage(^(const Image* image, bool& stop) {
951 if ( image->hasPathWithHash(path, hash) ) {
952 num = image->imageNum();
953 found = true;
954 stop = true;
955 }
956 });
957 return found;
958 }
959
960 const Image* ImageArray::imageForNum(ImageNum num) const
961 {
962 if (hasRoots) {
963 __block const Image* foundImage = nullptr;
964 forEachImage(^(const Image *image, bool &stop) {
965 if (image->imageNum() == num) {
966 foundImage = image;
967 stop = true;
968 }
969 });
970 return foundImage;
971 }
972 if ( num < firstImageNum )
973 return nullptr;
974
975 uint32_t index = num - firstImageNum;
976 if ( index >= count )
977 return nullptr;
978
979 return (Image*)((uint8_t*)payload() + offsets[index]);
980 }
981
982 const Image* ImageArray::findImage(const Array<const ImageArray*> imagesArrays, ImageNum imageNum)
983 {
984 // Search image arrays backwards as the main closure, or dlopen closures, may rebuild closures
985 // for shared cache images which are not roots, but whose initialisers must rebuild as they depend
986 // on a root
987 for (uintptr_t index = imagesArrays.count(); index > 0; --index) {
988 const ImageArray* ia = imagesArrays[index - 1];
989 if ( const Image* result = ia->imageForNum(imageNum) )
990 return result;
991 }
992 return nullptr;
993 }
994
995 void ImageArray::deallocate() const
996 {
997 ::vm_deallocate(mach_task_self(), (long)this, size());
998 }
999
1000 //////////////////////////// Closure ////////////////////////////////////////
1001
1002 size_t Closure::size() const
1003 {
1004 return sizeof(TypedBytes) + this->payloadLength;
1005 }
1006
1007 const ImageArray* Closure::images() const
1008 {
1009 __block const TypedBytes* result = nullptr;
1010 forEachAttribute(^(const TypedBytes* typedBytes, bool& stop) {
1011 if ( (Type)(typedBytes->type) == Type::imageArray ) {
1012 result = typedBytes;
1013 stop = true;
1014 }
1015 });
1016
1017 return (ImageArray*)result;
1018 }
1019
1020 ImageNum Closure::topImageNum() const
1021 {
1022 uint32_t size;
1023 const ImageNum* top = (ImageNum*)findAttributePayload(Type::topImage, &size);
1024 assert(top != nullptr);
1025 assert(size == sizeof(ImageNum));
1026 return *top;
1027 }
1028
1029 const Image* Closure::topImage() const
1030 {
1031 ImageNum imageNum = this->topImageNum();
1032 const dyld3::closure::ImageArray* closureImages = this->images();
1033 return closureImages->imageForNum(imageNum);
1034 }
1035
1036 void Closure::forEachPatchEntry(void (^handler)(const PatchEntry& entry)) const
1037 {
1038 forEachAttributePayload(Type::cacheOverrides, ^(const void* payload, uint32_t size, bool& stop) {
1039 assert((size % sizeof(Closure::PatchEntry)) == 0);
1040 const PatchEntry* patches = (PatchEntry*)payload;
1041 const PatchEntry* patchesEnd = (PatchEntry*)((char*)payload + size);
1042 for (const PatchEntry* p=patches; p < patchesEnd; ++p)
1043 handler(*p);
1044 });
1045 }
1046
1047 void Closure::forEachWarning(Closure::Warning::Type type, void (^handler)(const char* warning, bool& stop)) const
1048 {
1049 forEachAttributePayload(Type::warning, ^(const void* payload, uint32_t size, bool& stop) {
1050 const Closure::Warning* warning = (const Closure::Warning*)payload;
1051 if ( warning->type != type )
1052 return;
1053 handler(warning->message, stop);
1054 });
1055 }
1056
1057 void Closure::deallocate() const
1058 {
1059 ::vm_deallocate(mach_task_self(), (long)this, size());
1060 }
1061
1062
1063 //////////////////////////// LaunchClosure ////////////////////////////////////////
1064
1065 void LaunchClosure::forEachMustBeMissingFile(void (^handler)(const char* path, bool& stop)) const
1066 {
1067 uint32_t size;
1068 const char* paths = (const char*)findAttributePayload(Type::missingFiles, &size);
1069 bool stop = false;
1070 for (const char* s=paths; s < &paths[size]; ++s) {
1071 if ( *s != '\0' )
1072 handler(s, stop);
1073 if ( stop )
1074 break;
1075 s += strlen(s);
1076 }
1077 }
1078
1079 void LaunchClosure::forEachSkipIfExistsFile(void (^handler)(const SkippedFile& file, bool& stop)) const
1080 {
1081 uint32_t size;
1082 const uint64_t* files = (const uint64_t*)findAttributePayload(Type::existingFiles, &size);
1083 if (files == nullptr)
1084 return;
1085
1086 // The first entry is the length of the array
1087 uint64_t fileCount = *files++;
1088
1089 // Followed by count number of mod times and inodes
1090 const char* paths = (const char*)(files + (2 * fileCount));
1091 bool stop = false;
1092 for (const char* s=paths; s < &paths[size]; ++s) {
1093 if ( *s != '\0' ) {
1094 uint64_t inode = *files++;
1095 uint64_t mtime = *files++;
1096 SkippedFile skippedFile = { s, inode, mtime };
1097 handler(skippedFile, stop);
1098 }
1099 if ( stop )
1100 break;
1101 s += strlen(s);
1102 }
1103 }
1104
1105 bool LaunchClosure::builtAgainstDyldCache(uuid_t cacheUUID) const
1106 {
1107 uint32_t size;
1108 const uint8_t* uuidBytes = (uint8_t*)findAttributePayload(Type::dyldCacheUUID, &size);
1109 if ( uuidBytes == nullptr )
1110 return false;
1111 assert(size == sizeof(uuid_t));
1112 memcpy(cacheUUID, uuidBytes, sizeof(uuid_t));
1113 return true;
1114 }
1115
1116 void LaunchClosure::forEachEnvVar(void (^handler)(const char* keyEqualValue, bool& stop)) const
1117 {
1118 forEachAttributePayload(Type::envVar, ^(const void* payload, uint32_t size, bool& stop) {
1119 handler((char*)payload, stop);
1120 });
1121 }
1122
1123 ImageNum LaunchClosure::libSystemImageNum() const
1124 {
1125 uint32_t size;
1126 const ImageNum* num = (ImageNum*)findAttributePayload(Type::libSystemNum, &size);
1127 assert(num != nullptr);
1128 assert(size == sizeof(ImageNum));
1129 return *num;
1130 }
1131
1132 void LaunchClosure::libDyldEntry(Image::ResolvedSymbolTarget& loc) const
1133 {
1134 uint32_t size;
1135 const Image::ResolvedSymbolTarget* data = (Image::ResolvedSymbolTarget*)findAttributePayload(Type::libDyldEntry, &size);
1136 assert(data != nullptr);
1137 assert(size == sizeof(Image::ResolvedSymbolTarget));
1138 loc = *data;
1139 }
1140
1141 bool LaunchClosure::mainEntry(Image::ResolvedSymbolTarget& mainLoc) const
1142 {
1143 uint32_t size;
1144 const Image::ResolvedSymbolTarget* data = (Image::ResolvedSymbolTarget*)findAttributePayload(Type::mainEntry, &size);
1145 if ( data == nullptr )
1146 return false;
1147 assert(size == sizeof(Image::ResolvedSymbolTarget));
1148 mainLoc = *data;
1149 return true;
1150 }
1151
1152 bool LaunchClosure::startEntry(Image::ResolvedSymbolTarget& startLoc) const
1153 {
1154 uint32_t size;
1155 const Image::ResolvedSymbolTarget* data = (Image::ResolvedSymbolTarget*)findAttributePayload(Type::startEntry, &size);
1156 if ( data == nullptr )
1157 return false;
1158 assert(size == sizeof(Image::ResolvedSymbolTarget));
1159 startLoc = *data;
1160 return true;
1161 }
1162
1163 const LaunchClosure::Flags& LaunchClosure::getFlags() const
1164 {
1165 uint32_t size;
1166 const Flags* flags = (Flags*)findAttributePayload(Type::closureFlags, &size);
1167 assert(flags != nullptr && "Closure missing Flags");
1168 return *flags;
1169 }
1170
1171 uint32_t LaunchClosure::initialLoadCount() const
1172 {
1173 return getFlags().initImageCount;
1174 }
1175
1176 bool LaunchClosure::usedAtPaths() const
1177 {
1178 return getFlags().usedAtPaths;
1179 }
1180
1181 bool LaunchClosure::usedFallbackPaths() const
1182 {
1183 return getFlags().usedFallbackPaths;
1184 }
1185
1186 bool LaunchClosure::hasInsertedLibraries() const
1187 {
1188 return getFlags().hasInsertedLibraries;
1189 }
1190
1191 bool LaunchClosure::hasProgramVars(uint32_t& runtimeOffset) const
1192 {
1193 if ( !getFlags().hasProgVars )
1194 return false;
1195 uint32_t payloadSize = 0;
1196 const uint8_t* buffer = (const uint8_t*)findAttributePayload(Type::progVars, &payloadSize);
1197 if (buffer == nullptr)
1198 return false;
1199 runtimeOffset = *((uint32_t*)buffer);
1200 return true;
1201 }
1202
1203 bool LaunchClosure::usedInterposing() const
1204 {
1205 return getFlags().usedInterposing;
1206 }
1207
1208 bool LaunchClosure::hasInterposings() const
1209 {
1210 __block bool result = false;
1211
1212 forEachInterposingTuple(^(const InterposingTuple&, bool& stop) {
1213 result = true;
1214 stop = true;
1215 });
1216
1217 return result;
1218 }
1219
1220 void LaunchClosure::forEachInterposingTuple(void (^handler)(const InterposingTuple& tuple, bool& stop)) const
1221 {
1222 forEachAttributePayload(Type::interposeTuples, ^(const void* payload, uint32_t size, bool& stop) {
1223 assert((size % sizeof(InterposingTuple)) == 0);
1224 uintptr_t count = size / sizeof(InterposingTuple);
1225 const InterposingTuple* tuples = (InterposingTuple*)payload;
1226 for (uint32_t i=0; i < count && !stop; ++i) {
1227 handler(tuples[i], stop);
1228 }
1229 });
1230 }
1231 bool LaunchClosure::selectorHashTable(Array<Image::ObjCSelectorImage>& imageNums,
1232 const closure::ObjCSelectorOpt*& hashTable) const {
1233 uint32_t payloadSize = 0;
1234 const uint8_t* buffer = (const uint8_t*)findAttributePayload(Type::selectorTable, &payloadSize);
1235 if (buffer == nullptr)
1236 return false;
1237
1238 // Get count
1239 uint32_t count = 0;
1240 memcpy(&count, buffer, sizeof(uint32_t));
1241 buffer += sizeof(uint32_t);
1242
1243 // Get image nums
1244 imageNums = Array<Image::ObjCSelectorImage>((Image::ObjCSelectorImage*)buffer, count, count);
1245 buffer += sizeof(Image::ObjCSelectorImage) * count;
1246
1247 // Get hash table
1248 hashTable = (const closure::ObjCSelectorOpt*)buffer;
1249
1250 return true;
1251 }
1252
1253 bool LaunchClosure::classAndProtocolHashTables(Array<Image::ObjCClassImage>& imageNums,
1254 const ObjCClassOpt*& classHashTable,
1255 const ObjCClassOpt*& protocolHashTable) const {
1256 // The layout here is:
1257 // uint32_t offset to class table (note this is 0 if there are no classes)
1258 // uint32_t offset to protocol table (note this is 0 if there are no protocols)
1259 // uint32_t num images
1260 // ObjCClassImage[num images]
1261 // class hash table
1262 // [ padding to 4-byte alignment if needed
1263 // protocol hash table
1264 // [ padding to 4-byte alignment if needed
1265
1266 uint32_t payloadSize = 0;
1267 const uint8_t* buffer = (const uint8_t*)findAttributePayload(Type::classTable, &payloadSize);
1268 if (buffer == nullptr)
1269 return false;
1270
1271 uint32_t headerSize = sizeof(uint32_t) * 3;
1272
1273 uint32_t offsetToClassTable = 0;
1274 uint32_t offsetToProtocolTable = 0;
1275 uint32_t numImages = 0;
1276
1277 // Get the header
1278 memcpy(&offsetToClassTable, buffer + 0, sizeof(uint32_t));
1279 memcpy(&offsetToProtocolTable, buffer + 4, sizeof(uint32_t));
1280 memcpy(&numImages, buffer + 8, sizeof(uint32_t));
1281
1282 // Get the image nums
1283 imageNums = Array<Image::ObjCClassImage>((Image::ObjCClassImage*)(buffer + headerSize), numImages, numImages);
1284
1285 // Get the class hash table if there is one
1286 if ( offsetToClassTable != 0 )
1287 classHashTable = (const ObjCClassOpt*)(buffer + offsetToClassTable);
1288
1289 // Write out out the protocol hash table if there is one
1290 if ( offsetToProtocolTable != 0 )
1291 protocolHashTable = (const ObjCClassOpt*)(buffer + offsetToProtocolTable);
1292
1293 return true;
1294 }
1295
1296 void LaunchClosure::duplicateClassesHashTable(const ObjCClassDuplicatesOpt*& duplicateClassesHashTable) const {
1297 uint32_t payloadSize = 0;
1298 const uint8_t* buffer = (const uint8_t*)findAttributePayload(Type::duplicateClassesTable, &payloadSize);
1299 if (buffer == nullptr)
1300 return;
1301
1302 duplicateClassesHashTable = (const ObjCClassDuplicatesOpt*)buffer;
1303 }
1304
1305
1306 static bool getContainerLibraryCachesDir(const char* envp[], char libCacheDir[])
1307 {
1308 // $HOME is root of writable data container
1309 const char* homeDir = _simple_getenv(envp, "HOME");
1310 if ( homeDir == nullptr )
1311 return false;
1312
1313 // Use realpath to block malicious values like HOME=/tmp/../usr/bin
1314 char realHomePath[PATH_MAX];
1315 if ( realpath(homeDir, realHomePath) != nullptr )
1316 homeDir = realHomePath;
1317 #if TARGET_OS_OSX
1318 // <rdar://problem/66593232> iOS apps on Apple Silicon macOS have a different data container location
1319 if ( strstr(homeDir, "/Library/Containers/") == nullptr )
1320 return false;
1321 #else
1322 // <rdar://problem/47688842> dyld3 should only save closures to disk for containerized apps
1323 if ( strncmp(homeDir, "/private/var/mobile/Containers/Data/", 36) != 0 )
1324 return false;
1325 #endif
1326
1327 // return $HOME/Library/Caches/
1328 strlcpy(libCacheDir, homeDir, PATH_MAX);
1329 strlcat(libCacheDir, "/Library/Caches", PATH_MAX);
1330 return true;
1331 }
1332
1333 bool LaunchClosure::buildClosureCachePath(const char* mainExecutablePath, const char* envp[],
1334 bool makeDirsIfMissing, char closurePath[])
1335 {
1336 // get path to data container's Library/Caches/ dir
1337 if ( !getContainerLibraryCachesDir(envp, closurePath) )
1338 return false;
1339
1340 // make sure XXX/Library/Caches/ exists
1341 struct stat statbuf;
1342 if ( dyld3::stat(closurePath, &statbuf) != 0 )
1343 return false;
1344
1345 // add dyld sub-dir
1346 strlcat(closurePath, "/com.apple.dyld", PATH_MAX);
1347 if ( makeDirsIfMissing ) {
1348 if ( dyld3::stat(closurePath, &statbuf) != 0 ) {
1349 if ( ::mkdir(closurePath, S_IRWXU) != 0 )
1350 return false;
1351 }
1352 }
1353
1354 // add <prog-name> + ".closure"
1355 const char* leafName = strrchr(mainExecutablePath, '/');
1356 if ( leafName == nullptr )
1357 leafName = mainExecutablePath;
1358 else
1359 ++leafName;
1360 strlcat(closurePath, "/", PATH_MAX);
1361 strlcat(closurePath, leafName, PATH_MAX);
1362
1363 strlcat(closurePath, ".closure", PATH_MAX);
1364 return true;
1365 }
1366
1367
1368 //////////////////////////// ObjCStringTable ////////////////////////////////////////
1369
1370 uint32_t ObjCStringTable::hash(const char *key, size_t keylen) const
1371 {
1372 uint64_t val = objc_opt::lookup8((uint8_t*)key, keylen, salt);
1373 uint32_t index = (uint32_t)((shift == 64) ? 0 : (val>>shift)) ^ scramble[tab[val&mask]];
1374 return index;
1375 }
1376
1377 const char* ObjCStringTable::getString(const char* selName, const Array<uintptr_t>& baseAddresses) const {
1378 StringTarget target = getPotentialTarget(selName);
1379 if (target == sentinelTarget)
1380 return nullptr;
1381
1382 dyld3::closure::Image::ObjCImageOffset imageAndOffset;
1383 imageAndOffset.raw = target;
1384
1385 uintptr_t sectionBaseAddress = baseAddresses[imageAndOffset.imageIndex];
1386
1387 const char* value = (const char*)(sectionBaseAddress + imageAndOffset.imageOffset);
1388 if (!strcmp(selName, value))
1389 return value;
1390 return nullptr;
1391 }
1392
1393 //////////////////////////// ObjCSelectorOpt ////////////////////////////////////////
1394 bool ObjCSelectorOpt::getStringLocation(uint32_t index, const Array<closure::Image::ObjCSelectorImage>& selImages,
1395 ImageNum& imageNum, uint64_t& vmOffset) const {
1396 if ( index >= capacity )
1397 return false;
1398
1399 StringTarget target = targets()[index];
1400 if ( target == indexNotFound )
1401 return false;
1402
1403 dyld3::closure::Image::ObjCImageOffset imageAndOffset;
1404 imageAndOffset.raw = target;
1405
1406 imageNum = selImages[imageAndOffset.imageIndex].imageNum;
1407 vmOffset = selImages[imageAndOffset.imageIndex].offset + imageAndOffset.imageOffset;
1408 return true;;
1409 }
1410
1411 void ObjCSelectorOpt::forEachString(const Array<Image::ObjCSelectorImage>& selectorImages,
1412 void (^callback)(uint64_t selVMOffset, ImageNum imageNum)) const {
1413 dyld3::Array<StringTarget> stringTargets = targets();
1414 for (unsigned i = 0; i != capacity; ++i) {
1415 dyld3::closure::Image::ObjCImageOffset imageAndOffset;
1416 imageAndOffset.raw = stringTargets[i];
1417
1418 if (imageAndOffset.raw == sentinelTarget)
1419 continue;
1420
1421 callback(selectorImages[imageAndOffset.imageIndex].offset + imageAndOffset.imageOffset,
1422 selectorImages[imageAndOffset.imageIndex].imageNum);
1423 }
1424 }
1425
1426 //////////////////////////// ObjCClassOpt ////////////////////////////////////////
1427
1428 void ObjCClassOpt::forEachClass(const char* className, const Array<std::pair<uintptr_t, uintptr_t>>& nameAndDataBaseAddresses,
1429 void (^callback)(void* classPtr, bool isLoaded, bool* stop)) const {
1430 uint32_t index = getIndex(className);
1431 if ( index == closure::ObjCStringTable::indexNotFound )
1432 return;
1433
1434 StringTarget target = targets()[index];
1435 if ( target == sentinelTarget )
1436 return;
1437
1438 // We have a potential target. First check if the name is an exact match given the hash matched
1439 closure::Image::ObjCImageOffset classNameImageAndOffset;
1440 classNameImageAndOffset.raw = target;
1441
1442 uintptr_t nameBaseAddress = 0;
1443 uintptr_t dataBaseAddress = 0;
1444 std::tie(nameBaseAddress, dataBaseAddress) = nameAndDataBaseAddresses[classNameImageAndOffset.imageIndex];
1445
1446 const char* value = (const char*)(nameBaseAddress + classNameImageAndOffset.imageOffset);
1447 if ( strcmp(className, value) != 0 )
1448 return;
1449
1450 // The name matched so now call the handler on all the classes for this name
1451 Array<closure::ObjCClassOpt::ClassTarget> classOffsetsArray = classOffsets();
1452 Array<closure::ObjCClassOpt::ClassTarget> duplicatesArray = duplicateOffsets(duplicateCount());
1453
1454 const closure::ObjCClassOpt::ClassTarget& classOffset = classOffsetsArray[index];
1455 if (classOffset.classData.isDuplicate == 0) {
1456 // This class has a single implementation
1457 void* classImpl = (void*)(dataBaseAddress + classOffset.classData.imageOffset);
1458 bool stop = false;
1459 callback(classImpl, true, &stop);
1460 } else {
1461 // This class has mulitple implementations
1462 uint32_t duplicateCount = classOffset.duplicateData.count;
1463 uint32_t duplicateStartIndex = classOffset.duplicateData.index;
1464 for (uint32_t dupeIndex = 0; dupeIndex != duplicateCount; ++dupeIndex) {
1465 closure::ObjCClassOpt::ClassTarget& duplicateClass = duplicatesArray[duplicateStartIndex + dupeIndex];
1466
1467 std::tie(nameBaseAddress, dataBaseAddress) = nameAndDataBaseAddresses[duplicateClass.classData.imageIndex];
1468 void* classImpl = (void*)(dataBaseAddress + duplicateClass.classData.imageOffset);
1469 bool stop = false;
1470 callback(classImpl, true, &stop);
1471 if (stop)
1472 break;
1473 }
1474 }
1475 }
1476
1477 void ObjCClassOpt::forEachClass(const Array<Image::ObjCClassImage>& classImages,
1478 void (^nameCallback)(uint64_t classNameVMOffset, ImageNum imageNum),
1479 void (^implCallback)(uint64_t classVMOffset, ImageNum imageNum)) const {
1480
1481 dyld3::Array<StringTarget> stringTargets = targets();
1482 dyld3::Array<ObjCClassOpt::ClassTarget> classOffsetsArray = classOffsets();
1483 dyld3::Array<ObjCClassOpt::ClassTarget> duplicatesArray = duplicateOffsets(duplicateCount());
1484 for (unsigned i = 0; i != capacity; ++i) {
1485 dyld3::closure::Image::ObjCImageOffset classNameImageAndOffset;
1486 classNameImageAndOffset.raw = stringTargets[i];
1487
1488 if (classNameImageAndOffset.raw == sentinelTarget)
1489 continue;
1490
1491 nameCallback(classImages[classNameImageAndOffset.imageIndex].offsetOfClassNames + classNameImageAndOffset.imageOffset,
1492 classImages[classNameImageAndOffset.imageIndex].imageNum);
1493
1494 // Walk each class for this key
1495 const ObjCClassOpt::ClassTarget& classOffset = classOffsetsArray[i];
1496 if (classOffset.classData.isDuplicate == 0) {
1497 // This class has a single implementation
1498 implCallback(classImages[classOffset.classData.imageIndex].offsetOfClasses + classOffset.classData.imageOffset,
1499 classImages[classOffset.classData.imageIndex].imageNum);
1500 } else {
1501 // This class has mulitple implementations
1502 uint32_t duplicateCount = classOffset.duplicateData.count;
1503 uint32_t duplicateStartIndex = classOffset.duplicateData.index;
1504 for (uint32_t dupeIndex = 0; dupeIndex != duplicateCount; ++dupeIndex) {
1505 ObjCClassOpt::ClassTarget& duplicateClass = duplicatesArray[duplicateStartIndex + dupeIndex];
1506 implCallback(classImages[duplicateClass.classData.imageIndex].offsetOfClasses + duplicateClass.classData.imageOffset,
1507 classImages[duplicateClass.classData.imageIndex].imageNum);
1508 }
1509 }
1510 }
1511 }
1512
1513 //////////////////////////// ObjCClassDuplicatesOpt ////////////////////////////////////////
1514
1515 bool ObjCClassDuplicatesOpt::getClassLocation(const char* className, const objc_opt::objc_opt_t* objCOpt, void*& classImpl) const {
1516 uint32_t potentialTarget = getPotentialTarget(className);
1517 if (potentialTarget == sentinelTarget)
1518 return false;
1519
1520 objc_opt::objc_clsopt_t* clsOpt = objCOpt->clsopt();
1521
1522 Image::ObjCDuplicateClass duplicateClass;
1523 duplicateClass.raw = potentialTarget;
1524
1525 const char* sharedCacheClassName = clsOpt->getClassNameForIndex(duplicateClass.sharedCacheClassOptIndex);
1526 if (strcmp(className, sharedCacheClassName) != 0)
1527 return false;
1528
1529 classImpl = clsOpt->getClassForIndex(duplicateClass.sharedCacheClassOptIndex, duplicateClass.sharedCacheClassDuplicateIndex);
1530 return true;
1531 }
1532
1533 void ObjCClassDuplicatesOpt::forEachClass(void (^callback)(Image::ObjCDuplicateClass duplicateClass)) const {
1534 dyld3::Array<StringTarget> stringTargets = targets();
1535 for (unsigned i = 0; i != capacity; ++i) {
1536 StringTarget target = stringTargets[i];
1537 if ( target == sentinelTarget )
1538 continue;
1539 Image::ObjCDuplicateClass duplicateClass;
1540 duplicateClass.raw = (uint32_t)target;
1541 callback(duplicateClass);
1542 }
1543 }
1544
1545
1546 } // namespace closure
1547 } // namespace dyld3
1548
1549
1550