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