dyld-655.1.1.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
31 #include "Closure.h"
32 #include "MachOFile.h"
33 #include "MachOLoaded.h"
34
35
36 namespace dyld {
37 extern void log(const char* format, ...) __attribute__((format(printf, 1, 2)));
38 }
39
40 namespace dyld3 {
41 namespace closure {
42
43
44 //////////////////////////// TypedBytes ////////////////////////////////////////
45
46 const void* TypedBytes::payload() const
47 {
48 return (uint8_t*)this + sizeof(TypedBytes);
49 }
50
51 void* TypedBytes::payload()
52 {
53 return (uint8_t*)this + sizeof(TypedBytes);
54 }
55
56
57 //////////////////////////// ContainerTypedBytes ////////////////////////////////////////
58
59 const TypedBytes* ContainerTypedBytes::first() const
60 {
61 return (TypedBytes*)payload();
62 }
63
64 const TypedBytes* ContainerTypedBytes::next(const TypedBytes* p) const
65 {
66 assert((p->payloadLength & 0x3) == 0);
67 return (TypedBytes*)((uint8_t*)(p->payload()) + p->payloadLength);
68 }
69
70 void ContainerTypedBytes::forEachAttribute(void (^handler)(const TypedBytes* typedBytes, bool& stop)) const
71 {
72 assert(((long)this & 0x3) == 0);
73 const TypedBytes* end = next(this);
74 bool stop = false;
75 for (const TypedBytes* p = first(); p < end && !stop; p = next(p)) {
76 handler(p, stop);
77 }
78 }
79
80 void ContainerTypedBytes::forEachAttributePayload(Type requestedType, void (^handler)(const void* payload, uint32_t size, bool& stop)) const
81 {
82 forEachAttribute(^(const TypedBytes* typedBytes, bool& stop) {
83 if ( (Type)(typedBytes->type) != requestedType )
84 return;
85 handler(typedBytes->payload(), typedBytes->payloadLength, stop);
86 });
87 }
88
89 const void* ContainerTypedBytes::findAttributePayload(Type requestedType, uint32_t* payloadSize) const
90 {
91 assert(((long)this & 0x3) == 0);
92 if ( payloadSize != nullptr )
93 *payloadSize = 0;
94 const TypedBytes* end = next(this);
95 bool stop = false;
96 for (const TypedBytes* p = first(); p < end && !stop; p = next(p)) {
97 if ( (Type)(p->type) == requestedType ) {
98 if ( payloadSize != nullptr )
99 *payloadSize = p->payloadLength;
100 return p->payload();
101 }
102 }
103 return nullptr;
104 }
105
106
107 //////////////////////////// Image ////////////////////////////////////////
108
109 const Image::Flags& Image::getFlags() const
110 {
111 return *(Flags*)((uint8_t*)this + 2*sizeof(TypedBytes));
112 }
113
114 bool Image::isInvalid() const
115 {
116 return getFlags().isInvalid;
117 }
118
119 size_t Image::size() const
120 {
121 return sizeof(TypedBytes) + this->payloadLength;
122 }
123
124 ImageNum Image::imageNum() const
125 {
126 return getFlags().imageNum;
127 }
128
129 // returns true iff 'num' is this image's ImageNum, or this image overrides that imageNum (in dyld cache)
130 bool Image::representsImageNum(ImageNum num) const
131 {
132 const Flags& flags = getFlags();
133 if ( flags.imageNum == num )
134 return true;
135 if ( !flags.isDylib )
136 return false;
137 if ( flags.inDyldCache )
138 return false;
139 ImageNum cacheImageNum;
140 if ( isOverrideOfDyldCacheImage(cacheImageNum) )
141 return (cacheImageNum == num);
142 return false;
143 }
144
145 uint32_t Image::maxLoadCount() const
146 {
147 return getFlags().maxLoadCount;
148 }
149
150 bool Image::isBundle() const
151 {
152 return getFlags().isBundle;
153 }
154
155 bool Image::isDylib() const
156 {
157 return getFlags().isDylib;
158 }
159
160 bool Image::isExecutable() const
161 {
162 return getFlags().isExecutable;
163 }
164
165 bool Image::hasObjC() const
166 {
167 return getFlags().hasObjC;
168 }
169
170 bool Image::is64() const
171 {
172 return getFlags().is64;
173 }
174
175 bool Image::hasWeakDefs() const
176 {
177 return getFlags().hasWeakDefs;
178 }
179
180 bool Image::mayHavePlusLoads() const
181 {
182 return getFlags().mayHavePlusLoads;
183 }
184
185 bool Image::neverUnload() const
186 {
187 return getFlags().neverUnload;
188 }
189
190 bool Image::overridableDylib() const
191 {
192 return getFlags().overridableDylib;
193 }
194
195 bool Image::inDyldCache() const
196 {
197 return getFlags().inDyldCache;
198 }
199
200 const char* Image::path() const
201 {
202 // might be multiple pathWithHash enties, first is canonical name
203 const PathAndHash* result = (PathAndHash*)findAttributePayload(Type::pathWithHash);
204 assert(result && "Image missing pathWithHash");
205 return result->path;
206 }
207
208 const char* Image::leafName() const
209 {
210 uint32_t size;
211 // might be multiple pathWithHash enties, first is canonical name
212 const PathAndHash* result = (PathAndHash*)findAttributePayload(Type::pathWithHash, &size);
213 assert(result && "Image missing pathWithHash");
214 for (const char* p=(char*)result + size; p > result->path; --p) {
215 if ( *p == '/' )
216 return p+1;
217 }
218 return result->path;
219 }
220
221 bool Image::hasFileModTimeAndInode(uint64_t& inode, uint64_t& mTime) const
222 {
223 uint32_t size;
224 const FileInfo* info = (FileInfo*)(findAttributePayload(Type::fileInodeAndTime, &size));
225 if ( info != nullptr ) {
226 assert(size == sizeof(FileInfo));
227 inode = info->inode;
228 mTime = info->modTime;
229 return true;
230 }
231 return false;
232 }
233
234 bool Image::hasCdHash(uint8_t cdHash[20]) const
235 {
236 uint32_t size;
237 const uint8_t* bytes = (uint8_t*)(findAttributePayload(Type::cdHash, &size));
238 if ( bytes != nullptr ) {
239 assert(size == 20);
240 memcpy(cdHash, bytes, 20);
241 return true;
242 }
243 return false;
244 }
245
246 bool Image::getUuid(uuid_t uuid) const
247 {
248 uint32_t size;
249 const uint8_t* bytes = (uint8_t*)(findAttributePayload(Type::uuid, &size));
250 if ( bytes == nullptr )
251 return false;
252 assert(size == 16);
253 memcpy(uuid, bytes, 16);
254 return true;
255 }
256
257 bool Image::hasCodeSignature(uint32_t& sigFileOffset, uint32_t& sigSize) const
258 {
259 uint32_t sz;
260 const Image::CodeSignatureLocation* sigInfo = (Image::CodeSignatureLocation*)(findAttributePayload(Type::codeSignLoc, &sz));
261 if ( sigInfo != nullptr ) {
262 assert(sz == sizeof(Image::CodeSignatureLocation));
263 sigFileOffset = sigInfo->fileOffset;
264 sigSize = sigInfo->fileSize;
265 return true;
266 }
267 return false;
268 }
269
270 bool Image::isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const
271 {
272 uint32_t sz;
273 const Image::FairPlayRange* fpInfo = (Image::FairPlayRange*)(findAttributePayload(Type::fairPlayLoc, &sz));
274 if ( fpInfo != nullptr ) {
275 assert(sz == sizeof(Image::FairPlayRange));
276 textOffset = fpInfo->textStartPage * pageSize();
277 size = fpInfo->textPageCount * pageSize();
278 return true;
279 }
280 return false;
281 }
282
283 const Array<Image::LinkedImage> Image::dependentsArray() const
284 {
285 uint32_t size;
286 LinkedImage* dependents = (LinkedImage*)findAttributePayload(Type::dependents, &size);
287 assert((size % sizeof(LinkedImage)) == 0);
288 uintptr_t count = size / sizeof(LinkedImage);
289 return Array<Image::LinkedImage>(dependents, count, count);
290 }
291
292 void Image::forEachDependentImage(void (^handler)(uint32_t dependentIndex, LinkKind kind, ImageNum imageNum, bool& stop)) const
293 {
294 uint32_t size;
295 const LinkedImage* dependents = (LinkedImage*)findAttributePayload(Type::dependents, &size);
296 assert((size % sizeof(LinkedImage)) == 0);
297 const uint32_t count = size / sizeof(LinkedImage);
298 bool stop = false;
299 for (uint32_t i=0; (i < count) && !stop; ++i) {
300 LinkKind kind = dependents[i].kind();
301 ImageNum imageNum = dependents[i].imageNum();
302 // ignore missing weak links
303 if ( (imageNum == kMissingWeakLinkedImage) && (kind == LinkKind::weak) )
304 continue;
305 handler(i, kind, imageNum, stop);
306 }
307 }
308
309 ImageNum Image::dependentImageNum(uint32_t depIndex) const
310 {
311 uint32_t size;
312 const LinkedImage* dependents = (LinkedImage*)findAttributePayload(Type::dependents, &size);
313 assert((size % sizeof(LinkedImage)) == 0);
314 const uint32_t count = size / sizeof(LinkedImage);
315 assert(depIndex < count);
316 return dependents[depIndex].imageNum();
317 }
318
319
320 uint32_t Image::hashFunction(const char* str)
321 {
322 uint32_t h = 0;
323 for (const char* s=str; *s != '\0'; ++s)
324 h = h*5 + *s;
325 return h;
326 }
327
328 void Image::forEachAlias(void (^handler)(const char* aliasPath, bool& stop)) const
329 {
330 __block bool foundFirst = false;
331 forEachAttribute(^(const TypedBytes* typedBytes, bool& stopLoop) {
332 if ( (Type)(typedBytes->type) != Type::pathWithHash )
333 return;
334 if ( foundFirst ) {
335 const PathAndHash* aliasInfo = (PathAndHash*)typedBytes->payload();
336 handler(aliasInfo->path, stopLoop);
337 }
338 else {
339 foundFirst = true;
340 }
341 });
342 }
343
344 bool Image::hasPathWithHash(const char* path, uint32_t hash) const
345 {
346 __block bool found = false;
347 forEachAttribute(^(const TypedBytes* typedBytes, bool& stop) {
348 if ( (Type)(typedBytes->type) != Type::pathWithHash )
349 return;
350 const PathAndHash* pathInfo = (PathAndHash*)typedBytes->payload();
351 if ( (pathInfo->hash == hash) && (strcmp(path, pathInfo->path) == 0) ) {
352 stop = true;
353 found = true;
354 }
355 });
356 return found;
357 }
358
359 void Image::forEachDiskSegment(void (^handler)(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const
360 {
361 uint32_t size;
362 const DiskSegment* segments = (DiskSegment*)findAttributePayload(Type::diskSegment, &size);
363 assert(segments != nullptr);
364 assert((size % sizeof(DiskSegment)) == 0);
365 const uint32_t count = size / sizeof(DiskSegment);
366 const uint32_t pageSz = pageSize();
367 uint32_t segIndex = 0;
368 uint32_t fileOffset = 0;
369 int64_t vmOffset = 0;
370 // decrement vmOffset by all segments before TEXT (e.g. PAGEZERO)
371 for (uint32_t i=0; i < count; ++i) {
372 const DiskSegment* seg = &segments[i];
373 if ( seg->filePageCount != 0 ) {
374 break;
375 }
376 vmOffset -= (uint64_t)seg->vmPageCount * pageSz;
377 }
378 // walk each segment and call handler
379 bool stop = false;
380 for (uint32_t i=0; i < count && !stop; ++i) {
381 const DiskSegment* seg = &segments[i];
382 uint64_t vmSize = (uint64_t)seg->vmPageCount * pageSz;
383 uint32_t fileSize = seg->filePageCount * pageSz;
384 if ( !seg->paddingNotSeg ) {
385 handler(segIndex, ( fileSize == 0) ? 0 : fileOffset, fileSize, vmOffset, vmSize, seg->permissions, stop);
386 ++segIndex;
387 }
388 vmOffset += vmSize;
389 fileOffset += fileSize;
390 }
391 }
392
393 uint32_t Image::pageSize() const
394 {
395 if ( getFlags().has16KBpages )
396 return 0x4000;
397 else
398 return 0x1000;
399 }
400
401 uint32_t Image::cacheOffset() const
402 {
403 uint32_t size;
404 const DyldCacheSegment* segments = (DyldCacheSegment*)findAttributePayload(Type::cacheSegment, &size);
405 assert(segments != nullptr);
406 assert((size % sizeof(DyldCacheSegment)) == 0);
407 return segments[0].cacheOffset;
408 }
409
410 void Image::forEachCacheSegment(void (^handler)(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const
411 {
412 uint32_t size;
413 const DyldCacheSegment* segments = (DyldCacheSegment*)findAttributePayload(Type::cacheSegment, &size);
414 assert(segments != nullptr);
415 assert((size % sizeof(DyldCacheSegment)) == 0);
416 const uint32_t count = size / sizeof(DyldCacheSegment);
417 bool stop = false;
418 for (uint32_t i=0; i < count; ++i) {
419 uint64_t vmOffset = segments[i].cacheOffset - segments[0].cacheOffset;
420 uint64_t vmSize = segments[i].size;
421 uint8_t permissions = segments[i].permissions;
422 handler(i, vmOffset, vmSize, permissions, stop);
423 if ( stop )
424 break;
425 }
426 }
427
428 uint64_t Image::textSize() const
429 {
430 __block uint64_t result = 0;
431 if ( inDyldCache() ) {
432 forEachCacheSegment(^(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop) {
433 result = vmSize;
434 stop = true;
435 });
436 }
437 else {
438 forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop) {
439 if ( permissions != 0) {
440 result = vmSize;
441 stop = true;
442 }
443 });
444 }
445 return result;
446 }
447
448 bool Image::containsAddress(const void* addr, const void* imageLoadAddress, uint8_t* permsResult) const
449 {
450 __block bool result = false;
451 uint64_t targetAddr = (uint64_t)addr;
452 uint64_t imageStart = (uint64_t)imageLoadAddress;
453 if ( inDyldCache() ) {
454 forEachCacheSegment(^(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop) {
455 if ( (targetAddr >= imageStart+vmOffset) && (targetAddr < imageStart+vmOffset+vmSize) ) {
456 result = true;
457 if ( permsResult )
458 *permsResult = permissions;
459 stop = true;
460 }
461 });
462 }
463 else {
464 forEachDiskSegment(^(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop) {
465 if ( (targetAddr >= imageStart+vmOffset) && (targetAddr < imageStart+vmOffset+vmSize) ) {
466 result = true;
467 if ( permsResult )
468 *permsResult = permissions;
469 stop = true;
470 }
471 });
472 }
473 return result;
474 }
475
476 uint64_t Image::vmSizeToMap() const
477 {
478 uint32_t size;
479 const Image::MappingInfo* info = (Image::MappingInfo*)(findAttributePayload(Type::mappingInfo, &size));
480 assert(info != nullptr);
481 assert(size == sizeof(Image::MappingInfo));
482 return info->totalVmPages * pageSize();
483 }
484
485 uint64_t Image::sliceOffsetInFile() const
486 {
487 uint32_t size;
488 const Image::MappingInfo* info = (Image::MappingInfo*)(findAttributePayload(Type::mappingInfo, &size));
489 assert(info != nullptr);
490 assert(size == sizeof(Image::MappingInfo));
491 return info->sliceOffsetIn4K * 0x1000;
492 }
493
494 void Image::forEachInitializer(const void* imageLoadAddress, void (^handler)(const void* initializer)) const
495 {
496 uint32_t size;
497 const uint32_t* inits = (uint32_t*)findAttributePayload(Type::initOffsets, &size);
498 if ( inits != nullptr ) {
499 assert((size % sizeof(uint32_t)) == 0);
500 const uint32_t count = size / sizeof(uint32_t);
501 for (uint32_t i=0; i < count; ++i) {
502 uint32_t offset = inits[i];
503 const void* init = (void*)((uint8_t*)imageLoadAddress + offset);
504 handler(init);
505 }
506 }
507 }
508
509 bool Image::hasInitializers() const
510 {
511 uint32_t size;
512 return ( findAttributePayload(Type::initOffsets, &size) != nullptr );
513 }
514
515 void Image::forEachDOF(const void* imageLoadAddress, void (^handler)(const void* dofSection)) const
516 {
517 uint32_t size;
518 const uint32_t* dofs = (uint32_t*)findAttributePayload(Type::dofOffsets, &size);
519 if ( dofs != nullptr ) {
520 assert((size % sizeof(uint32_t)) == 0);
521 const uint32_t count = size / sizeof(uint32_t);
522 for (uint32_t i=0; i < count; ++i) {
523 uint32_t offset = dofs[i];
524 const void* sect = (void*)((uint8_t*)imageLoadAddress + offset);
525 handler(sect);
526 }
527 }
528 }
529
530 void Image::forEachPatchableExport(void (^handler)(uint32_t cacheOffsetOfImpl, const char* exportName)) const
531 {
532 forEachAttributePayload(Type::cachePatchInfo, ^(const void* payload, uint32_t size, bool& stop) {
533 const Image::PatchableExport* pe = (Image::PatchableExport*)payload;
534 assert(size > (sizeof(Image::PatchableExport) + pe->patchLocationsCount*sizeof(PatchableExport::PatchLocation)));
535 handler(pe->cacheOffsetOfImpl, (char*)(&pe->patchLocations[pe->patchLocationsCount]));
536 });
537 }
538
539 void Image::forEachPatchableUseOfExport(uint32_t cacheOffsetOfImpl, void (^handler)(PatchableExport::PatchLocation patchLocation)) const
540 {
541 forEachAttributePayload(Type::cachePatchInfo, ^(const void* payload, uint32_t size, bool& stop) {
542 const Image::PatchableExport* pe = (Image::PatchableExport*)payload;
543 assert(size > (sizeof(Image::PatchableExport) + pe->patchLocationsCount*sizeof(PatchableExport::PatchLocation)));
544 if ( pe->cacheOffsetOfImpl != cacheOffsetOfImpl )
545 return;
546 const PatchableExport::PatchLocation* start = pe->patchLocations;
547 const PatchableExport::PatchLocation* end = &start[pe->patchLocationsCount];
548 for (const PatchableExport::PatchLocation* p=start; p < end; ++p)
549 handler(*p);
550 });
551 }
552
553 uint32_t Image::patchableExportCount() const
554 {
555 __block uint32_t count = 0;
556 forEachAttributePayload(Type::cachePatchInfo, ^(const void* payload, uint32_t size, bool& stop) {
557 ++count;
558 });
559 return count;
560 }
561
562 void Image::forEachFixup(void (^rebase)(uint64_t imageOffsetToRebase, bool& stop),
563 void (^bind)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
564 void (^chainedFixupsStart)(uint64_t imageOffsetStart, const Array<ResolvedSymbolTarget>& targets, bool& stop)) const
565 {
566 const uint32_t pointerSize = is64() ? 8 : 4;
567 uint64_t curRebaseOffset = 0;
568 bool stop = false;
569 for (const Image::RebasePattern& rebasePat : rebaseFixups()) {
570 //fprintf(stderr, " repeat=0x%04X, contig=%d, skip=%d\n", rebasePat.repeatCount, rebasePat.contigCount, rebasePat.skipCount);
571 if ( rebasePat.contigCount == 0 ) {
572 // note: contigCount==0 means this just advances location
573 if ( (rebasePat.repeatCount == 0) && (rebasePat.skipCount == 0) ) {
574 // all zeros is special pattern that means reset to rebase offset to zero
575 curRebaseOffset = 0;
576 }
577 else {
578 curRebaseOffset += rebasePat.repeatCount * rebasePat.skipCount;
579 }
580 }
581 else {
582 for (int r=0; r < rebasePat.repeatCount && !stop; ++r) {
583 for (int i=0; i < rebasePat.contigCount && !stop; ++i) {
584 //fprintf(stderr, " 0x%08llX\n", curRebaseOffset);
585 rebase(curRebaseOffset, stop);
586 curRebaseOffset += pointerSize;
587 }
588 curRebaseOffset += pointerSize * rebasePat.skipCount;
589 }
590 }
591 if ( stop )
592 break;
593 }
594 if ( stop )
595 return;
596
597 for (const Image::BindPattern& bindPat : bindFixups()) {
598 uint64_t curBindOffset = bindPat.startVmOffset;
599 for (uint16_t i=0; i < bindPat.repeatCount; ++i) {
600 bind(curBindOffset, bindPat.target, stop);
601 curBindOffset += (pointerSize * (1 + bindPat.skipCount));
602 if ( stop )
603 break;
604 }
605 if ( stop )
606 break;
607 }
608
609 const Array<Image::ResolvedSymbolTarget> targetsArray = chainedTargets();
610 for (uint64_t start : chainedStarts()) {
611 chainedFixupsStart(start, targetsArray, stop);
612 if ( stop )
613 break;
614 }
615 }
616
617 void Image::forEachChainedFixup(void* imageLoadAddress, uint64_t imageOffsetChainStart, void (^callback)(uint64_t* fixUpLoc, ChainedFixupPointerOnDisk fixupInfo, bool& stop))
618 {
619 bool stop = false;
620 uint64_t* fixupLoc = (uint64_t*)((uint8_t*)imageLoadAddress + imageOffsetChainStart);
621 do {
622 // save off current entry as it will be overwritten in callback
623 ChainedFixupPointerOnDisk info = *((ChainedFixupPointerOnDisk*)fixupLoc);
624 callback(fixupLoc, info, stop);
625 if ( info.plainRebase.next != 0 )
626 fixupLoc += info.plainRebase.next;
627 else
628 stop = true;
629 } while (!stop);
630 }
631
632 void Image::forEachTextReloc(void (^rebase)(uint32_t imageOffsetToRebase, bool& stop),
633 void (^bind)(uint32_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop)) const
634 {
635 bool stop = false;
636 const Array<Image::TextFixupPattern> f = textFixups();
637 for (const Image::TextFixupPattern& pat : f) {
638 uint32_t curOffset = pat.startVmOffset;
639 for (uint16_t i=0; i < pat.repeatCount; ++i) {
640 if ( pat.target.raw == 0 )
641 rebase(curOffset, stop);
642 else
643 bind(curOffset, pat.target, stop);
644 curOffset += pat.skipCount;
645 }
646 }
647 }
648
649 const Array<Image::RebasePattern> Image::rebaseFixups() const
650 {
651 uint32_t rebaseFixupsSize;
652 Image::RebasePattern* rebaseFixupsContent = (RebasePattern*)findAttributePayload(Type::rebaseFixups, &rebaseFixupsSize);
653 uint32_t rebaseCount = rebaseFixupsSize/sizeof(RebasePattern);
654 return Array<RebasePattern>(rebaseFixupsContent, rebaseCount, rebaseCount);
655 }
656
657 const Array<Image::BindPattern> Image::bindFixups() const
658 {
659 uint32_t bindFixupsSize;
660 BindPattern* bindFixupsContent = (BindPattern*)findAttributePayload(Type::bindFixups, &bindFixupsSize);
661 uint32_t bindCount = bindFixupsSize/sizeof(BindPattern);
662 return Array<BindPattern>(bindFixupsContent, bindCount, bindCount);
663 }
664
665 const Array<uint64_t> Image::chainedStarts() const
666 {
667 uint32_t startsSize;
668 uint64_t* starts = (uint64_t*)findAttributePayload(Type::chainedFixupsStarts, &startsSize);
669 uint32_t count = startsSize/sizeof(uint64_t);
670 return Array<uint64_t>(starts, count, count);
671 }
672
673 const Array<Image::ResolvedSymbolTarget> Image::chainedTargets() const
674 {
675 uint32_t size;
676 ResolvedSymbolTarget* targetsContent = (ResolvedSymbolTarget*)findAttributePayload(Type::chainedFixupsTargets, &size);
677 uint32_t count = size/sizeof(ResolvedSymbolTarget);
678 return Array<ResolvedSymbolTarget>(targetsContent, count, count);
679 }
680
681 const Array<Image::TextFixupPattern> Image::textFixups() const
682 {
683 uint32_t fixupsSize;
684 TextFixupPattern* fixupsContent = (TextFixupPattern*)findAttributePayload(Type::textFixups, &fixupsSize);
685 uint32_t count = fixupsSize/sizeof(TextFixupPattern);
686 return Array<TextFixupPattern>(fixupsContent, count, count);
687 }
688
689 bool Image::isOverrideOfDyldCacheImage(ImageNum& imageNum) const
690 {
691 uint32_t size;
692 const uint32_t* content = (uint32_t*)findAttributePayload(Type::imageOverride, &size);
693 if ( content != nullptr ) {
694 assert(size == sizeof(uint32_t));
695 imageNum = *content;
696 return true;
697 }
698 return false;
699 }
700
701 void Image::forEachImageToInitBefore(void (^handler)(ImageNum imageToInit, bool& stop)) const
702 {
703 uint32_t size;
704 const ImageNum* initBefores = (ImageNum*)findAttributePayload(Type::initBefores, &size);
705 if ( initBefores != nullptr ) {
706 assert((size % sizeof(ImageNum)) == 0);
707 const uint32_t count = size / sizeof(ImageNum);
708 bool stop = false;
709 for (uint32_t i=0; (i < count) && !stop; ++i) {
710 handler(initBefores[i], stop);
711 }
712 }
713 }
714
715 const char* Image::PatchableExport::PatchLocation::keyName() const
716 {
717 return MachOLoaded::ChainedFixupPointerOnDisk::keyName(this->key);
718 }
719
720 Image::PatchableExport::PatchLocation::PatchLocation(size_t cacheOff, uint64_t ad)
721 : cacheOffset(cacheOff), addend(ad), authenticated(0), usesAddressDiversity(0), key(0), discriminator(0)
722 {
723 int64_t signedAddend = (int64_t)ad;
724 assert(((signedAddend << 52) >> 52) == signedAddend);
725 }
726
727 Image::PatchableExport::PatchLocation::PatchLocation(size_t cacheOff, uint64_t ad, dyld3::MachOLoaded::ChainedFixupPointerOnDisk authInfo)
728 : cacheOffset(cacheOff), addend(ad), authenticated(authInfo.authBind.auth), usesAddressDiversity(authInfo.authBind.addrDiv), key(authInfo.authBind.key), discriminator(authInfo.authBind.diversity)
729 {
730 int64_t signedAddend = (int64_t)ad;
731 assert(((signedAddend << 52) >> 52) == signedAddend);
732 }
733
734 //////////////////////////// ImageArray ////////////////////////////////////////
735
736 size_t ImageArray::size() const
737 {
738 return sizeof(TypedBytes) + this->payloadLength;
739 }
740
741 size_t ImageArray::startImageNum() const
742 {
743 return firstImageNum;
744 }
745
746 uint32_t ImageArray::imageCount() const
747 {
748 return count;
749 }
750
751 void ImageArray::forEachImage(void (^callback)(const Image* image, bool& stop)) const
752 {
753 bool stop = false;
754 for (uint32_t i=0; i < count && !stop; ++i) {
755 const Image* image = (Image*)((uint8_t*)payload() + offsets[i]);
756 callback(image, stop);
757 if (stop)
758 break;
759 }
760 }
761
762 bool ImageArray::hasPath(const char* path, ImageNum& num) const
763 {
764 const uint32_t hash = Image::hashFunction(path);
765 __block bool found = false;
766 forEachImage(^(const Image* image, bool& stop) {
767 if ( image->hasPathWithHash(path, hash) ) {
768 num = image->imageNum();
769 found = true;
770 stop = true;
771 }
772 });
773 return found;
774 }
775
776 const Image* ImageArray::imageForNum(ImageNum num) const
777 {
778 if ( num < firstImageNum )
779 return nullptr;
780
781 uint32_t index = num - firstImageNum;
782 if ( index >= count )
783 return nullptr;
784
785 return (Image*)((uint8_t*)payload() + offsets[index]);
786 }
787
788 const Image* ImageArray::findImage(const Array<const ImageArray*> imagesArrays, ImageNum imageNum)
789 {
790 for (const ImageArray* ia : imagesArrays) {
791 if ( const Image* result = ia->imageForNum(imageNum) )
792 return result;
793 }
794 return nullptr;
795 }
796
797 //////////////////////////// Closure ////////////////////////////////////////
798
799 size_t Closure::size() const
800 {
801 return sizeof(TypedBytes) + this->payloadLength;
802 }
803
804 const ImageArray* Closure::images() const
805 {
806 __block const TypedBytes* result = nullptr;
807 forEachAttribute(^(const TypedBytes* typedBytes, bool& stop) {
808 if ( (Type)(typedBytes->type) == Type::imageArray ) {
809 result = typedBytes;
810 stop = true;
811 }
812 });
813
814 return (ImageArray*)result;
815 }
816
817 ImageNum Closure::topImage() const
818 {
819 uint32_t size;
820 const ImageNum* top = (ImageNum*)findAttributePayload(Type::topImage, &size);
821 assert(top != nullptr);
822 assert(size == sizeof(ImageNum));
823 return *top;
824 }
825
826 void Closure::forEachPatchEntry(void (^handler)(const PatchEntry& entry)) const
827 {
828 forEachAttributePayload(Type::cacheOverrides, ^(const void* payload, uint32_t size, bool& stop) {
829 assert((size % sizeof(Closure::PatchEntry)) == 0);
830 const PatchEntry* patches = (PatchEntry*)payload;
831 const PatchEntry* patchesEnd = (PatchEntry*)((char*)payload + size);
832 for (const PatchEntry* p=patches; p < patchesEnd; ++p)
833 handler(*p);
834 });
835 }
836
837 void Closure::deallocate() const
838 {
839 ::vm_deallocate(mach_task_self(), (long)this, size());
840 }
841
842 //////////////////////////// LaunchClosure ////////////////////////////////////////
843
844 void LaunchClosure::forEachMustBeMissingFile(void (^handler)(const char* path, bool& stop)) const
845 {
846 uint32_t size;
847 const char* paths = (const char*)findAttributePayload(Type::missingFiles, &size);
848 bool stop = false;
849 for (const char* s=paths; s < &paths[size]; ++s) {
850 if ( *s != '\0' )
851 handler(s, stop);
852 if ( stop )
853 break;
854 s += strlen(s);
855 }
856 }
857
858 bool LaunchClosure::builtAgainstDyldCache(uuid_t cacheUUID) const
859 {
860 uint32_t size;
861 const uint8_t* uuidBytes = (uint8_t*)findAttributePayload(Type::dyldCacheUUID, &size);
862 if ( uuidBytes == nullptr )
863 return false;
864 assert(size == sizeof(uuid_t));
865 memcpy(cacheUUID, uuidBytes, sizeof(uuid_t));
866 return true;
867 }
868
869 const char* LaunchClosure::bootUUID() const
870 {
871 uint32_t size;
872 return (char*)findAttributePayload(Type::bootUUID, &size);
873 }
874
875 void LaunchClosure::forEachEnvVar(void (^handler)(const char* keyEqualValue, bool& stop)) const
876 {
877 forEachAttributePayload(Type::envVar, ^(const void* payload, uint32_t size, bool& stop) {
878 handler((char*)payload, stop);
879 });
880 }
881
882 ImageNum LaunchClosure::libSystemImageNum() const
883 {
884 uint32_t size;
885 const ImageNum* num = (ImageNum*)findAttributePayload(Type::libSystemNum, &size);
886 assert(num != nullptr);
887 assert(size == sizeof(ImageNum));
888 return *num;
889 }
890
891 void LaunchClosure::libDyldEntry(Image::ResolvedSymbolTarget& loc) const
892 {
893 uint32_t size;
894 const Image::ResolvedSymbolTarget* data = (Image::ResolvedSymbolTarget*)findAttributePayload(Type::libDyldEntry, &size);
895 assert(data != nullptr);
896 assert(size == sizeof(Image::ResolvedSymbolTarget));
897 loc = *data;
898 }
899
900 bool LaunchClosure::mainEntry(Image::ResolvedSymbolTarget& mainLoc) const
901 {
902 uint32_t size;
903 const Image::ResolvedSymbolTarget* data = (Image::ResolvedSymbolTarget*)findAttributePayload(Type::mainEntry, &size);
904 if ( data == nullptr )
905 return false;
906 assert(size == sizeof(Image::ResolvedSymbolTarget));
907 mainLoc = *data;
908 return true;
909 }
910
911 bool LaunchClosure::startEntry(Image::ResolvedSymbolTarget& startLoc) const
912 {
913 uint32_t size;
914 const Image::ResolvedSymbolTarget* data = (Image::ResolvedSymbolTarget*)findAttributePayload(Type::startEntry, &size);
915 if ( data == nullptr )
916 return false;
917 assert(size == sizeof(Image::ResolvedSymbolTarget));
918 startLoc = *data;
919 return true;
920 }
921
922 const LaunchClosure::Flags& LaunchClosure::getFlags() const
923 {
924 uint32_t size;
925 const Flags* flags = (Flags*)findAttributePayload(Type::closureFlags, &size);
926 assert(flags != nullptr && "Closure missing Flags");
927 return *flags;
928 }
929
930 uint32_t LaunchClosure::initialLoadCount() const
931 {
932 return getFlags().initImageCount;
933 }
934
935 bool LaunchClosure::usedAtPaths() const
936 {
937 return getFlags().usedAtPaths;
938 }
939
940 bool LaunchClosure::usedFallbackPaths() const
941 {
942 return getFlags().usedFallbackPaths;
943 }
944
945 void LaunchClosure::forEachInterposingTuple(void (^handler)(const InterposingTuple& tuple, bool& stop)) const
946 {
947 forEachAttributePayload(Type::interposeTuples, ^(const void* payload, uint32_t size, bool& stop) {
948 assert((size % sizeof(InterposingTuple)) == 0);
949 uintptr_t count = size / sizeof(InterposingTuple);
950 const InterposingTuple* tuples = (InterposingTuple*)payload;
951 for (uint32_t i=0; i < count && !stop; ++i) {
952 handler(tuples[i], stop);
953 }
954 });
955 }
956
957
958
959 } // namespace closure
960 } // namespace dyld3
961
962
963