2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
27 #include <uuid/uuid.h>
30 #include <mach-o/dyld_priv.h>
32 #include <sys/sysctl.h>
33 #include <System/machine/cpu_capabilities.h>
36 #include <corecrypto/ccdigest.h>
37 #include <corecrypto/ccsha2.h>
41 #include "MachOFile.h"
42 #include "MachOLoaded.h"
43 #include "StringUtils.h"
45 #include "objc-shared-cache.h"
52 //////////////////////////// TypedBytes ////////////////////////////////////////
54 const void* TypedBytes::payload() const
56 return (uint8_t*)this + sizeof(TypedBytes
);
59 void* TypedBytes::payload()
61 return (uint8_t*)this + sizeof(TypedBytes
);
65 //////////////////////////// ContainerTypedBytes ////////////////////////////////////////
67 const TypedBytes
* ContainerTypedBytes::first() const
69 return (TypedBytes
*)payload();
72 const TypedBytes
* ContainerTypedBytes::next(const TypedBytes
* p
) const
74 assert((p
->payloadLength
& 0x3) == 0);
75 return (TypedBytes
*)((uint8_t*)(p
->payload()) + p
->payloadLength
);
78 void ContainerTypedBytes::forEachAttribute(void (^handler
)(const TypedBytes
* typedBytes
, bool& stop
)) const
80 assert(((long)this & 0x3) == 0);
81 const TypedBytes
* end
= next(this);
83 for (const TypedBytes
* p
= first(); p
< end
&& !stop
; p
= next(p
)) {
88 void ContainerTypedBytes::forEachAttributePayload(Type requestedType
, void (^handler
)(const void* payload
, uint32_t size
, bool& stop
)) const
90 forEachAttribute(^(const TypedBytes
* typedBytes
, bool& stop
) {
91 if ( (Type
)(typedBytes
->type
) != requestedType
)
93 handler(typedBytes
->payload(), typedBytes
->payloadLength
, stop
);
97 const void* ContainerTypedBytes::findAttributePayload(Type requestedType
, uint32_t* payloadSize
) const
99 assert(((long)this & 0x3) == 0);
100 if ( payloadSize
!= nullptr )
102 const TypedBytes
* end
= next(this);
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
;
115 //////////////////////////// Image ////////////////////////////////////////
117 const Image::Flags
& Image::getFlags() const
119 return *(Flags
*)((uint8_t*)this + 2*sizeof(TypedBytes
));
122 bool Image::isInvalid() const
124 return getFlags().isInvalid
;
127 size_t Image::size() const
129 return sizeof(TypedBytes
) + this->payloadLength
;
132 ImageNum
Image::imageNum() const
134 return getFlags().imageNum
;
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
140 const Flags
& flags
= getFlags();
141 if ( flags
.imageNum
== num
)
143 if ( !flags
.isDylib
)
145 if ( flags
.inDyldCache
)
147 ImageNum cacheImageNum
;
148 if ( isOverrideOfDyldCacheImage(cacheImageNum
) )
149 return (cacheImageNum
== num
);
153 uint32_t Image::maxLoadCount() const
155 return getFlags().maxLoadCount
;
158 bool Image::isBundle() const
160 return getFlags().isBundle
;
163 bool Image::isDylib() const
165 return getFlags().isDylib
;
168 bool Image::isExecutable() const
170 return getFlags().isExecutable
;
173 bool Image::hasObjC() const
175 return getFlags().hasObjC
;
178 bool Image::is64() const
180 return getFlags().is64
;
183 bool Image::hasWeakDefs() const
185 return getFlags().hasWeakDefs
;
188 bool Image::mayHavePlusLoads() const
190 return getFlags().mayHavePlusLoads
;
193 bool Image::neverUnload() const
195 return getFlags().neverUnload
;
198 bool Image::overridableDylib() const
200 return getFlags().overridableDylib
;
203 bool Image::inDyldCache() const
205 return getFlags().inDyldCache
;
208 const char* Image::path() const
210 // might be multiple pathWithHash enties, first is canonical name
211 const PathAndHash
* result
= (PathAndHash
*)findAttributePayload(Type::pathWithHash
);
212 assert(result
&& "Image missing pathWithHash");
216 const char* Image::leafName() const
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
) {
229 bool Image::hasFileModTimeAndInode(uint64_t& inode
, uint64_t& mTime
) const
232 const FileInfo
* info
= (FileInfo
*)(findAttributePayload(Type::fileInodeAndTime
, &size
));
233 if ( info
!= nullptr ) {
234 assert(size
== sizeof(FileInfo
));
236 mTime
= info
->modTime
;
242 void Image::forEachCDHash(void (^handler
)(const uint8_t cdHash
[20], bool& stop
)) const
244 forEachAttribute(^(const TypedBytes
* typedBytes
, bool& stopLoop
) {
245 if ( (Type
)(typedBytes
->type
) != Type::cdHash
)
247 assert(typedBytes
->payloadLength
== 20);
248 const uint8_t* bytes
= (const uint8_t*)typedBytes
->payload();
249 handler(bytes
, stopLoop
);
253 bool Image::getUuid(uuid_t uuid
) const
256 const uint8_t* bytes
= (uint8_t*)(findAttributePayload(Type::uuid
, &size
));
257 if ( bytes
== nullptr )
260 memcpy(uuid
, bytes
, 16);
264 bool Image::hasCodeSignature(uint32_t& sigFileOffset
, uint32_t& sigSize
) const
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
;
277 bool Image::isFairPlayEncrypted(uint32_t& textOffset
, uint32_t& size
) const
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
;
290 const Array
<Image::LinkedImage
> Image::dependentsArray() const
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
);
299 void Image::forEachDependentImage(void (^handler
)(uint32_t dependentIndex
, LinkKind kind
, ImageNum imageNum
, bool& stop
)) const
302 const LinkedImage
* dependents
= (LinkedImage
*)findAttributePayload(Type::dependents
, &size
);
303 assert((size
% sizeof(LinkedImage
)) == 0);
304 const uint32_t count
= size
/ sizeof(LinkedImage
);
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
) )
312 handler(i
, kind
, imageNum
, stop
);
316 ImageNum
Image::dependentImageNum(uint32_t depIndex
) const
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();
327 uint32_t Image::hashFunction(const char* str
)
330 for (const char* s
=str
; *s
!= '\0'; ++s
)
335 void Image::forEachAlias(void (^handler
)(const char* aliasPath
, bool& stop
)) const
337 __block
bool foundFirst
= false;
338 forEachAttribute(^(const TypedBytes
* typedBytes
, bool& stopLoop
) {
339 if ( (Type
)(typedBytes
->type
) != Type::pathWithHash
)
342 const PathAndHash
* aliasInfo
= (PathAndHash
*)typedBytes
->payload();
343 handler(aliasInfo
->path
, stopLoop
);
351 bool Image::hasPathWithHash(const char* path
, uint32_t hash
) const
353 __block
bool found
= false;
354 forEachAttribute(^(const TypedBytes
* typedBytes
, bool& stop
) {
355 if ( (Type
)(typedBytes
->type
) != Type::pathWithHash
)
357 const PathAndHash
* pathInfo
= (PathAndHash
*)typedBytes
->payload();
358 if ( (pathInfo
->hash
== hash
) && (strcmp(path
, pathInfo
->path
) == 0) ) {
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
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 ) {
384 vmOffset
-= (uint64_t)seg
->vmPageCount
* pageSz
;
386 // walk each segment and call handler
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
;
400 handler(segIndex
, ( fileSize
== 0) ? 0 : fileOffset
, fileSize
, vmOffset
, vmSize
, perms
, laterRO
, stop
);
404 fileOffset
+= fileSize
;
408 uint32_t Image::pageSize() const
410 if ( getFlags().has16KBpages
)
416 uint32_t Image::cacheOffset() const
419 const DyldCacheSegment
* segments
= (DyldCacheSegment
*)findAttributePayload(Type::cacheSegment
, &size
);
420 assert(segments
!= nullptr);
421 assert((size
% sizeof(DyldCacheSegment
)) == 0);
422 return segments
[0].cacheOffset
;
425 void Image::forEachCacheSegment(void (^handler
)(uint32_t segIndex
, uint64_t vmOffset
, uint64_t vmSize
, uint8_t permissions
, bool& stop
)) const
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
);
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
);
443 uint64_t Image::textSize() const
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
) {
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) {
463 bool Image::containsAddress(const void* addr
, const void* imageLoadAddress
, uint8_t* permsResult
) const
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
) ) {
473 *permsResult
= permissions
;
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
) ) {
483 *permsResult
= permissions
;
491 uint64_t Image::vmSizeToMap() const
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();
500 uint64_t Image::sliceOffsetInFile() const
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;
509 void Image::forEachInitializer(const void* imageLoadAddress
, void (^handler
)(const void* initializer
)) const
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
);
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
]));
533 handler((void*)(long)(start32
[i
]));
538 bool Image::forEachInitializerSection(void (^handler
)(uint32_t sectionOffset
, uint32_t sectionSize
)) const
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
);
550 bool Image::hasInitializers() const
553 return ( findAttributePayload(Type::initOffsets
, &size
) != nullptr );
556 bool Image::hasTerminators() const
558 return getFlags().hasTerminators
;
561 bool Image::hasReadOnlyData() const
563 return getFlags().hasReadOnlyData
;
566 bool Image::hasChainedFixups() const
568 return getFlags().hasChainedFixups
;
571 bool Image::hasPrecomputedObjC() const
573 return getFlags().hasPrecomputedObjC
;
576 void Image::forEachTerminator(const void* imageLoadAddress
, void (^handler
)(const void* terminator
)) const
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
);
591 void Image::forEachDOF(const void* imageLoadAddress
, void (^handler
)(const void* dofSection
)) const
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
);
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
615 const uint32_t pointerSize
= is64() ? 8 : 4;
616 uint64_t curRebaseOffset
= 0;
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
627 curRebaseOffset
+= rebasePat
.repeatCount
* rebasePat
.skipCount
;
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
;
637 curRebaseOffset
+= pointerSize
* rebasePat
.skipCount
;
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
));
658 if (hasChainedFixups())
659 chainedFixups(chainedStartsOffset(), chainedTargets(), stop
);
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
);
671 // Set the objc image info bit to tell libobjc we are optimized
672 fixupObjCImageInfo(objcImageInfoVMOffset
);
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
));
688 for (uintptr_t i
= 0, e
= selRefFixupEntries
.count(); i
!= e
; ++i
) {
689 Image::SelectorReferenceFixup fixupEntry
= selRefFixupEntries
[i
];
691 uint64_t curFixupOffset
= fixupEntry
.chainStartVMOffset
;
692 // Now walk the chain until we get a 'next' of 0
694 fixupEntry
= selRefFixupEntries
[++i
];
695 fixupObjCSelRef(curFixupOffset
, fixupEntry
.chainEntry
.index
, fixupEntry
.chainEntry
.inSharedCache
, stop
);
698 if ( fixupEntry
.chainEntry
.next
== 0 )
700 curFixupOffset
+= (4 * fixupEntry
.chainEntry
.next
);
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
));
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
));
732 void Image::forEachTextReloc(void (^rebase
)(uint32_t imageOffsetToRebase
, bool& stop
),
733 void (^bind
)(uint32_t imageOffsetToBind
, ResolvedSymbolTarget bindTarget
, bool& stop
)) const
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
);
743 bind(curOffset
, pat
.target
, stop
);
744 curOffset
+= pat
.skipCount
;
749 const Array
<Image::RebasePattern
> Image::rebaseFixups() const
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
);
757 const Array
<Image::BindPattern
> Image::bindFixups() const
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
);
765 uint64_t Image::chainedStartsOffset() const
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
;
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
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
794 if (!hasPrecomputedObjC())
797 uint32_t contentSize
;
798 const uint8_t* fixupsContent
= (uint8_t*)findAttributePayload(Type::objcFixups
, &contentSize
);
799 const uint8_t* fixupsContentEnd
= fixupsContent
+ contentSize
;
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);
813 // Get the protocol fixups
814 if ( protocolFixupCount
!= 0) {
815 protocolISAFixups
= Array
<ProtocolISAFixup
>((ProtocolISAFixup
*)fixupsContent
, protocolFixupCount
, protocolFixupCount
);
816 fixupsContent
+= (sizeof(ProtocolISAFixup
) * protocolFixupCount
);
819 // Get the selector reference fixups
820 if ( selRefFixupCount
!= 0) {
821 selRefFixups
= Array
<SelectorReferenceFixup
>((SelectorReferenceFixup
*)fixupsContent
, selRefFixupCount
, selRefFixupCount
);
822 fixupsContent
+= (sizeof(SelectorReferenceFixup
) * selRefFixupCount
);
825 // Old closures end here, but newer ones might have additional fixups
826 if (fixupsContent
== fixupsContentEnd
)
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);
836 // Get the stable swift fixups
837 if ( stableSwiftFixupCount
!= 0) {
838 classStableSwiftFixups
= Array
<ClassStableSwiftFixup
>((ClassStableSwiftFixup
*)fixupsContent
, stableSwiftFixupCount
, stableSwiftFixupCount
);
839 fixupsContent
+= (sizeof(ClassStableSwiftFixup
) * stableSwiftFixupCount
);
842 // Get the method list fixups
843 if ( methodListFixupCount
!= 0) {
844 methodListFixups
= Array
<MethodListFixup
>((MethodListFixup
*)fixupsContent
, methodListFixupCount
, methodListFixupCount
);
845 fixupsContent
+= (sizeof(MethodListFixup
) * methodListFixupCount
);
849 const Array
<Image::ResolvedSymbolTarget
> Image::chainedTargets() const
852 ResolvedSymbolTarget
* targetsContent
= (ResolvedSymbolTarget
*)findAttributePayload(Type::chainedFixupsTargets
, &size
);
853 uint32_t count
= size
/sizeof(ResolvedSymbolTarget
);
854 return Array
<ResolvedSymbolTarget
>(targetsContent
, count
, count
);
857 const Array
<Image::TextFixupPattern
> Image::textFixups() const
860 TextFixupPattern
* fixupsContent
= (TextFixupPattern
*)findAttributePayload(Type::textFixups
, &fixupsSize
);
861 uint32_t count
= fixupsSize
/sizeof(TextFixupPattern
);
862 return Array
<TextFixupPattern
>(fixupsContent
, count
, count
);
865 bool Image::isOverrideOfDyldCacheImage(ImageNum
& imageNum
) const
868 const uint32_t* content
= (uint32_t*)findAttributePayload(Type::imageOverride
, &size
);
869 if ( content
!= nullptr ) {
870 assert(size
== sizeof(uint32_t));
877 void Image::forEachImageToInitBefore(void (^handler
)(ImageNum imageToInit
, bool& stop
)) const
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
);
885 for (uint32_t i
=0; (i
< count
) && !stop
; ++i
) {
886 handler(initBefores
[i
], stop
);
891 //////////////////////////// ImageArray ////////////////////////////////////////
893 size_t ImageArray::size() const
895 return sizeof(TypedBytes
) + this->payloadLength
;
898 size_t ImageArray::startImageNum() const
900 return firstImageNum
;
903 uint32_t ImageArray::imageCount() const
908 void ImageArray::forEachImage(void (^callback
)(const Image
* image
, bool& stop
)) const
911 for (uint32_t i
=0; i
< count
&& !stop
; ++i
) {
912 const Image
* image
= (Image
*)((uint8_t*)payload() + offsets
[i
]);
913 callback(image
, stop
);
919 bool ImageArray::hasPath(const char* path
, ImageNum
& num
) const
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();
933 const Image
* ImageArray::imageForNum(ImageNum num
) const
936 __block
const Image
* foundImage
= nullptr;
937 forEachImage(^(const Image
*image
, bool &stop
) {
938 if (image
->imageNum() == num
) {
945 if ( num
< firstImageNum
)
948 uint32_t index
= num
- firstImageNum
;
949 if ( index
>= count
)
952 return (Image
*)((uint8_t*)payload() + offsets
[index
]);
955 const Image
* ImageArray::findImage(const Array
<const ImageArray
*> imagesArrays
, ImageNum imageNum
)
957 for (const ImageArray
* ia
: imagesArrays
) {
958 if ( const Image
* result
= ia
->imageForNum(imageNum
) )
964 void ImageArray::deallocate() const
966 ::vm_deallocate(mach_task_self(), (long)this, size());
969 //////////////////////////// Closure ////////////////////////////////////////
971 size_t Closure::size() const
973 return sizeof(TypedBytes
) + this->payloadLength
;
976 const ImageArray
* Closure::images() const
978 __block
const TypedBytes
* result
= nullptr;
979 forEachAttribute(^(const TypedBytes
* typedBytes
, bool& stop
) {
980 if ( (Type
)(typedBytes
->type
) == Type::imageArray
) {
986 return (ImageArray
*)result
;
989 ImageNum
Closure::topImage() const
992 const ImageNum
* top
= (ImageNum
*)findAttributePayload(Type::topImage
, &size
);
993 assert(top
!= nullptr);
994 assert(size
== sizeof(ImageNum
));
998 void Closure::forEachPatchEntry(void (^handler
)(const PatchEntry
& entry
)) const
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
)
1009 void Closure::forEachWarning(Closure::Warning::Type type
, void (^handler
)(const char* warning
, bool& stop
)) const
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
)
1015 handler(warning
->message
, stop
);
1019 void Closure::deallocate() const
1021 ::vm_deallocate(mach_task_self(), (long)this, size());
1024 //////////////////////////// LaunchClosure ////////////////////////////////////////
1026 void LaunchClosure::forEachMustBeMissingFile(void (^handler
)(const char* path
, bool& stop
)) const
1029 const char* paths
= (const char*)findAttributePayload(Type::missingFiles
, &size
);
1031 for (const char* s
=paths
; s
< &paths
[size
]; ++s
) {
1040 void LaunchClosure::forEachSkipIfExistsFile(void (^handler
)(const SkippedFile
& file
, bool& stop
)) const
1043 const uint64_t* files
= (const uint64_t*)findAttributePayload(Type::existingFiles
, &size
);
1044 if (files
== nullptr)
1047 // The first entry is the length of the array
1048 uint64_t fileCount
= *files
++;
1050 // Followed by count number of mod times and inodes
1051 const char* paths
= (const char*)(files
+ (2 * fileCount
));
1053 for (const char* s
=paths
; s
< &paths
[size
]; ++s
) {
1055 uint64_t inode
= *files
++;
1056 uint64_t mtime
= *files
++;
1057 SkippedFile skippedFile
= { s
, inode
, mtime
};
1058 handler(skippedFile
, stop
);
1066 bool LaunchClosure::builtAgainstDyldCache(uuid_t cacheUUID
) const
1069 const uint8_t* uuidBytes
= (uint8_t*)findAttributePayload(Type::dyldCacheUUID
, &size
);
1070 if ( uuidBytes
== nullptr )
1072 assert(size
== sizeof(uuid_t
));
1073 memcpy(cacheUUID
, uuidBytes
, sizeof(uuid_t
));
1077 const char* LaunchClosure::bootUUID() const
1080 return (char*)findAttributePayload(Type::bootUUID
, &size
);
1083 void LaunchClosure::forEachEnvVar(void (^handler
)(const char* keyEqualValue
, bool& stop
)) const
1085 forEachAttributePayload(Type::envVar
, ^(const void* payload
, uint32_t size
, bool& stop
) {
1086 handler((char*)payload
, stop
);
1090 ImageNum
LaunchClosure::libSystemImageNum() const
1093 const ImageNum
* num
= (ImageNum
*)findAttributePayload(Type::libSystemNum
, &size
);
1094 assert(num
!= nullptr);
1095 assert(size
== sizeof(ImageNum
));
1099 void LaunchClosure::libDyldEntry(Image::ResolvedSymbolTarget
& loc
) const
1102 const Image::ResolvedSymbolTarget
* data
= (Image::ResolvedSymbolTarget
*)findAttributePayload(Type::libDyldEntry
, &size
);
1103 assert(data
!= nullptr);
1104 assert(size
== sizeof(Image::ResolvedSymbolTarget
));
1108 bool LaunchClosure::mainEntry(Image::ResolvedSymbolTarget
& mainLoc
) const
1111 const Image::ResolvedSymbolTarget
* data
= (Image::ResolvedSymbolTarget
*)findAttributePayload(Type::mainEntry
, &size
);
1112 if ( data
== nullptr )
1114 assert(size
== sizeof(Image::ResolvedSymbolTarget
));
1119 bool LaunchClosure::startEntry(Image::ResolvedSymbolTarget
& startLoc
) const
1122 const Image::ResolvedSymbolTarget
* data
= (Image::ResolvedSymbolTarget
*)findAttributePayload(Type::startEntry
, &size
);
1123 if ( data
== nullptr )
1125 assert(size
== sizeof(Image::ResolvedSymbolTarget
));
1130 const LaunchClosure::Flags
& LaunchClosure::getFlags() const
1133 const Flags
* flags
= (Flags
*)findAttributePayload(Type::closureFlags
, &size
);
1134 assert(flags
!= nullptr && "Closure missing Flags");
1138 uint32_t LaunchClosure::initialLoadCount() const
1140 return getFlags().initImageCount
;
1143 bool LaunchClosure::usedAtPaths() const
1145 return getFlags().usedAtPaths
;
1148 bool LaunchClosure::usedFallbackPaths() const
1150 return getFlags().usedFallbackPaths
;
1153 bool LaunchClosure::hasInsertedLibraries() const
1155 return getFlags().hasInsertedLibraries
;
1158 bool LaunchClosure::hasInterposings() const
1160 __block
bool result
= false;
1162 forEachInterposingTuple(^(const InterposingTuple
&, bool& stop
) {
1170 void LaunchClosure::forEachInterposingTuple(void (^handler
)(const InterposingTuple
& tuple
, bool& stop
)) const
1172 forEachAttributePayload(Type::interposeTuples
, ^(const void* payload
, uint32_t size
, bool& stop
) {
1173 assert((size
% sizeof(InterposingTuple
)) == 0);
1174 uintptr_t count
= size
/ sizeof(InterposingTuple
);
1175 const InterposingTuple
* tuples
= (InterposingTuple
*)payload
;
1176 for (uint32_t i
=0; i
< count
&& !stop
; ++i
) {
1177 handler(tuples
[i
], stop
);
1181 bool LaunchClosure::selectorHashTable(Array
<Image::ObjCSelectorImage
>& imageNums
,
1182 const closure::ObjCSelectorOpt
*& hashTable
) const {
1183 uint32_t payloadSize
= 0;
1184 const uint8_t* buffer
= (const uint8_t*)findAttributePayload(Type::selectorTable
, &payloadSize
);
1185 if (buffer
== nullptr)
1190 memcpy(&count
, buffer
, sizeof(uint32_t));
1191 buffer
+= sizeof(uint32_t);
1194 imageNums
= Array
<Image::ObjCSelectorImage
>((Image::ObjCSelectorImage
*)buffer
, count
, count
);
1195 buffer
+= sizeof(Image::ObjCSelectorImage
) * count
;
1198 hashTable
= (const closure::ObjCSelectorOpt
*)buffer
;
1203 bool LaunchClosure::classAndProtocolHashTables(Array
<Image::ObjCClassImage
>& imageNums
,
1204 const ObjCClassOpt
*& classHashTable
,
1205 const ObjCClassOpt
*& protocolHashTable
) const {
1206 // The layout here is:
1207 // uint32_t offset to class table (note this is 0 if there are no classes)
1208 // uint32_t offset to protocol table (note this is 0 if there are no protocols)
1209 // uint32_t num images
1210 // ObjCClassImage[num images]
1212 // [ padding to 4-byte alignment if needed
1213 // protocol hash table
1214 // [ padding to 4-byte alignment if needed
1216 uint32_t payloadSize
= 0;
1217 const uint8_t* buffer
= (const uint8_t*)findAttributePayload(Type::classTable
, &payloadSize
);
1218 if (buffer
== nullptr)
1221 uint32_t headerSize
= sizeof(uint32_t) * 3;
1223 uint32_t offsetToClassTable
= 0;
1224 uint32_t offsetToProtocolTable
= 0;
1225 uint32_t numImages
= 0;
1228 memcpy(&offsetToClassTable
, buffer
+ 0, sizeof(uint32_t));
1229 memcpy(&offsetToProtocolTable
, buffer
+ 4, sizeof(uint32_t));
1230 memcpy(&numImages
, buffer
+ 8, sizeof(uint32_t));
1232 // Get the image nums
1233 imageNums
= Array
<Image::ObjCClassImage
>((Image::ObjCClassImage
*)(buffer
+ headerSize
), numImages
, numImages
);
1235 // Get the class hash table if there is one
1236 if ( offsetToClassTable
!= 0 )
1237 classHashTable
= (const ObjCClassOpt
*)(buffer
+ offsetToClassTable
);
1239 // Write out out the protocol hash table if there is one
1240 if ( offsetToProtocolTable
!= 0 )
1241 protocolHashTable
= (const ObjCClassOpt
*)(buffer
+ offsetToProtocolTable
);
1246 void LaunchClosure::duplicateClassesHashTable(const ObjCClassDuplicatesOpt
*& duplicateClassesHashTable
) const {
1247 uint32_t payloadSize
= 0;
1248 const uint8_t* buffer
= (const uint8_t*)findAttributePayload(Type::duplicateClassesTable
, &payloadSize
);
1249 if (buffer
== nullptr)
1252 duplicateClassesHashTable
= (const ObjCClassDuplicatesOpt
*)buffer
;
1255 static void putHexNibble(uint8_t value
, char*& p
)
1260 *p
++ = 'A' + value
- 10;
1263 static void putHexByte(uint8_t value
, char*& p
)
1266 putHexNibble(value
>> 4, p
);
1267 putHexNibble(value
& 0x0F, p
);
1270 static bool hashBootAndFileInfo(const char* mainExecutablePath
, char hashString
[32])
1272 struct stat statbuf
;
1273 if ( ::stat(mainExecutablePath
, &statbuf
) != 0)
1275 #if !TARGET_OS_DRIVERKIT // Temp until core crypto is available
1276 const struct ccdigest_info
* di
= ccsha256_di();
1277 ccdigest_di_decl(di
, hashTemp
); // defines hashTemp array in stack
1278 ccdigest_init(di
, hashTemp
);
1280 // put boot time into hash
1281 const uint64_t* bootTime
= ((uint64_t*)_COMM_PAGE_BOOTTIME_USEC
);
1282 ccdigest_update(di
, hashTemp
, sizeof(uint64_t), bootTime
);
1284 // put inode of executable into hash
1285 ccdigest_update(di
, hashTemp
, sizeof(statbuf
.st_ino
), &statbuf
.st_ino
);
1287 // put mod-time of executable into hash
1288 ccdigest_update(di
, hashTemp
, sizeof(statbuf
.st_mtime
), &statbuf
.st_mtime
);
1290 // complete hash computation and append as hex string
1291 uint8_t hashBits
[32];
1292 ccdigest_final(di
, hashTemp
, hashBits
);
1293 char* s
= hashString
;
1294 for (size_t i
=0; i
< sizeof(hashBits
); ++i
)
1295 putHexByte(hashBits
[i
], s
);
1301 bool LaunchClosure::buildClosureCachePath(const char* mainExecutablePath
, char closurePath
[], const char* tempDir
,
1302 bool makeDirsIfMissing
)
1304 // <rdar://problem/47688842> dyld3 should only save closures to disk for containerized apps
1305 if ( strstr(tempDir
, "/Containers/Data/") == nullptr )
1308 strlcpy(closurePath
, tempDir
, PATH_MAX
);
1309 strlcat(closurePath
, "/com.apple.dyld/", PATH_MAX
);
1311 // make sure dyld sub-dir exists
1312 if ( makeDirsIfMissing
) {
1313 struct stat statbuf
;
1314 if ( ::stat(closurePath
, &statbuf
) != 0 ) {
1315 if ( ::mkdir(closurePath
, S_IRWXU
) != 0 )
1320 const char* leafName
= strrchr(mainExecutablePath
, '/');
1321 if ( leafName
== nullptr )
1322 leafName
= mainExecutablePath
;
1325 strlcat(closurePath
, leafName
, PATH_MAX
);
1326 strlcat(closurePath
, "-", PATH_MAX
);
1328 if ( !hashBootAndFileInfo(mainExecutablePath
, &closurePath
[strlen(closurePath
)]) )
1331 strlcat(closurePath
, ".closure", PATH_MAX
);
1335 //////////////////////////// ObjCStringTable ////////////////////////////////////////
1337 uint32_t ObjCStringTable::hash(const char *key
, size_t keylen
) const
1339 uint64_t val
= objc_opt::lookup8((uint8_t*)key
, keylen
, salt
);
1340 uint32_t index
= (uint32_t)((shift
== 64) ? 0 : (val
>>shift
)) ^ scramble
[tab
[val
&mask
]];
1344 const char* ObjCStringTable::getString(const char* selName
, const Array
<uintptr_t>& baseAddresses
) const {
1345 StringTarget target
= getPotentialTarget(selName
);
1346 if (target
== sentinelTarget
)
1349 dyld3::closure::Image::ObjCImageOffset imageAndOffset
;
1350 imageAndOffset
.raw
= target
;
1352 uintptr_t sectionBaseAddress
= baseAddresses
[imageAndOffset
.imageIndex
];
1354 const char* value
= (const char*)(sectionBaseAddress
+ imageAndOffset
.imageOffset
);
1355 if (!strcmp(selName
, value
))
1360 //////////////////////////// ObjCSelectorOpt ////////////////////////////////////////
1361 bool ObjCSelectorOpt::getStringLocation(uint32_t index
, const Array
<closure::Image::ObjCSelectorImage
>& selImages
,
1362 ImageNum
& imageNum
, uint64_t& vmOffset
) const {
1363 if ( index
>= capacity
)
1366 StringTarget target
= targets()[index
];
1367 if ( target
== indexNotFound
)
1370 dyld3::closure::Image::ObjCImageOffset imageAndOffset
;
1371 imageAndOffset
.raw
= target
;
1373 imageNum
= selImages
[imageAndOffset
.imageIndex
].imageNum
;
1374 vmOffset
= selImages
[imageAndOffset
.imageIndex
].offset
+ imageAndOffset
.imageOffset
;
1378 void ObjCSelectorOpt::forEachString(const Array
<Image::ObjCSelectorImage
>& selectorImages
,
1379 void (^callback
)(uint64_t selVMOffset
, ImageNum imageNum
)) const {
1380 dyld3::Array
<StringTarget
> stringTargets
= targets();
1381 for (unsigned i
= 0; i
!= capacity
; ++i
) {
1382 dyld3::closure::Image::ObjCImageOffset imageAndOffset
;
1383 imageAndOffset
.raw
= stringTargets
[i
];
1385 if (imageAndOffset
.raw
== sentinelTarget
)
1388 callback(selectorImages
[imageAndOffset
.imageIndex
].offset
+ imageAndOffset
.imageOffset
,
1389 selectorImages
[imageAndOffset
.imageIndex
].imageNum
);
1393 //////////////////////////// ObjCClassOpt ////////////////////////////////////////
1395 void ObjCClassOpt::forEachClass(const char* className
, const Array
<std::pair
<uintptr_t, uintptr_t>>& nameAndDataBaseAddresses
,
1396 void (^callback
)(void* classPtr
, bool isLoaded
, bool* stop
)) const {
1397 uint32_t index
= getIndex(className
);
1398 if ( index
== closure::ObjCStringTable::indexNotFound
)
1401 StringTarget target
= targets()[index
];
1402 if ( target
== sentinelTarget
)
1405 // We have a potential target. First check if the name is an exact match given the hash matched
1406 closure::Image::ObjCImageOffset classNameImageAndOffset
;
1407 classNameImageAndOffset
.raw
= target
;
1409 uintptr_t nameBaseAddress
= 0;
1410 uintptr_t dataBaseAddress
= 0;
1411 std::tie(nameBaseAddress
, dataBaseAddress
) = nameAndDataBaseAddresses
[classNameImageAndOffset
.imageIndex
];
1413 const char* value
= (const char*)(nameBaseAddress
+ classNameImageAndOffset
.imageOffset
);
1414 if ( strcmp(className
, value
) != 0 )
1417 // The name matched so now call the handler on all the classes for this name
1418 Array
<closure::ObjCClassOpt::ClassTarget
> classOffsetsArray
= classOffsets();
1419 Array
<closure::ObjCClassOpt::ClassTarget
> duplicatesArray
= duplicateOffsets(duplicateCount());
1421 const closure::ObjCClassOpt::ClassTarget
& classOffset
= classOffsetsArray
[index
];
1422 if (classOffset
.classData
.isDuplicate
== 0) {
1423 // This class has a single implementation
1424 void* classImpl
= (void*)(dataBaseAddress
+ classOffset
.classData
.imageOffset
);
1426 callback(classImpl
, true, &stop
);
1428 // This class has mulitple implementations
1429 uint32_t duplicateCount
= classOffset
.duplicateData
.count
;
1430 uint32_t duplicateStartIndex
= classOffset
.duplicateData
.index
;
1431 for (uint32_t dupeIndex
= 0; dupeIndex
!= duplicateCount
; ++dupeIndex
) {
1432 closure::ObjCClassOpt::ClassTarget
& duplicateClass
= duplicatesArray
[duplicateStartIndex
+ dupeIndex
];
1434 std::tie(nameBaseAddress
, dataBaseAddress
) = nameAndDataBaseAddresses
[duplicateClass
.classData
.imageIndex
];
1435 void* classImpl
= (void*)(dataBaseAddress
+ duplicateClass
.classData
.imageOffset
);
1437 callback(classImpl
, true, &stop
);
1444 void ObjCClassOpt::forEachClass(const Array
<Image::ObjCClassImage
>& classImages
,
1445 void (^nameCallback
)(uint64_t classNameVMOffset
, ImageNum imageNum
),
1446 void (^implCallback
)(uint64_t classVMOffset
, ImageNum imageNum
)) const {
1448 dyld3::Array
<StringTarget
> stringTargets
= targets();
1449 dyld3::Array
<ObjCClassOpt::ClassTarget
> classOffsetsArray
= classOffsets();
1450 dyld3::Array
<ObjCClassOpt::ClassTarget
> duplicatesArray
= duplicateOffsets(duplicateCount());
1451 for (unsigned i
= 0; i
!= capacity
; ++i
) {
1452 dyld3::closure::Image::ObjCImageOffset classNameImageAndOffset
;
1453 classNameImageAndOffset
.raw
= stringTargets
[i
];
1455 if (classNameImageAndOffset
.raw
== sentinelTarget
)
1458 nameCallback(classImages
[classNameImageAndOffset
.imageIndex
].offsetOfClassNames
+ classNameImageAndOffset
.imageOffset
,
1459 classImages
[classNameImageAndOffset
.imageIndex
].imageNum
);
1461 // Walk each class for this key
1462 const ObjCClassOpt::ClassTarget
& classOffset
= classOffsetsArray
[i
];
1463 if (classOffset
.classData
.isDuplicate
== 0) {
1464 // This class has a single implementation
1465 implCallback(classImages
[classOffset
.classData
.imageIndex
].offsetOfClasses
+ classOffset
.classData
.imageOffset
,
1466 classImages
[classOffset
.classData
.imageIndex
].imageNum
);
1468 // This class has mulitple implementations
1469 uint32_t duplicateCount
= classOffset
.duplicateData
.count
;
1470 uint32_t duplicateStartIndex
= classOffset
.duplicateData
.index
;
1471 for (uint32_t dupeIndex
= 0; dupeIndex
!= duplicateCount
; ++dupeIndex
) {
1472 ObjCClassOpt::ClassTarget
& duplicateClass
= duplicatesArray
[duplicateStartIndex
+ dupeIndex
];
1473 implCallback(classImages
[duplicateClass
.classData
.imageIndex
].offsetOfClasses
+ duplicateClass
.classData
.imageOffset
,
1474 classImages
[duplicateClass
.classData
.imageIndex
].imageNum
);
1480 //////////////////////////// ObjCClassDuplicatesOpt ////////////////////////////////////////
1482 bool ObjCClassDuplicatesOpt::getClassLocation(const char* className
, const objc_opt::objc_opt_t
* objCOpt
, void*& classImpl
) const {
1483 uint32_t potentialTarget
= getPotentialTarget(className
);
1484 if (potentialTarget
== sentinelTarget
)
1487 objc_opt::objc_clsopt_t
* clsOpt
= objCOpt
->clsopt();
1489 Image::ObjCDuplicateClass duplicateClass
;
1490 duplicateClass
.raw
= potentialTarget
;
1492 const char* sharedCacheClassName
= clsOpt
->getClassNameForIndex(duplicateClass
.sharedCacheClassOptIndex
);
1493 if (strcmp(className
, sharedCacheClassName
) != 0)
1496 classImpl
= clsOpt
->getClassForIndex(duplicateClass
.sharedCacheClassOptIndex
, duplicateClass
.sharedCacheClassDuplicateIndex
);
1500 void ObjCClassDuplicatesOpt::forEachClass(void (^callback
)(Image::ObjCDuplicateClass duplicateClass
)) const {
1501 dyld3::Array
<StringTarget
> stringTargets
= targets();
1502 for (unsigned i
= 0; i
!= capacity
; ++i
) {
1503 StringTarget target
= stringTargets
[i
];
1504 if ( target
== sentinelTarget
)
1506 Image::ObjCDuplicateClass duplicateClass
;
1507 duplicateClass
.raw
= (uint32_t)target
;
1508 callback(duplicateClass
);
1513 } // namespace closure
1514 } // namespace dyld3