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>
32 #include "MachOFile.h"
33 #include "MachOLoaded.h"
37 extern void log(const char* format
, ...) __attribute__((format(printf
, 1, 2)));
44 //////////////////////////// TypedBytes ////////////////////////////////////////
46 const void* TypedBytes::payload() const
48 return (uint8_t*)this + sizeof(TypedBytes
);
51 void* TypedBytes::payload()
53 return (uint8_t*)this + sizeof(TypedBytes
);
57 //////////////////////////// ContainerTypedBytes ////////////////////////////////////////
59 const TypedBytes
* ContainerTypedBytes::first() const
61 return (TypedBytes
*)payload();
64 const TypedBytes
* ContainerTypedBytes::next(const TypedBytes
* p
) const
66 assert((p
->payloadLength
& 0x3) == 0);
67 return (TypedBytes
*)((uint8_t*)(p
->payload()) + p
->payloadLength
);
70 void ContainerTypedBytes::forEachAttribute(void (^handler
)(const TypedBytes
* typedBytes
, bool& stop
)) const
72 assert(((long)this & 0x3) == 0);
73 const TypedBytes
* end
= next(this);
75 for (const TypedBytes
* p
= first(); p
< end
&& !stop
; p
= next(p
)) {
80 void ContainerTypedBytes::forEachAttributePayload(Type requestedType
, void (^handler
)(const void* payload
, uint32_t size
, bool& stop
)) const
82 forEachAttribute(^(const TypedBytes
* typedBytes
, bool& stop
) {
83 if ( (Type
)(typedBytes
->type
) != requestedType
)
85 handler(typedBytes
->payload(), typedBytes
->payloadLength
, stop
);
89 const void* ContainerTypedBytes::findAttributePayload(Type requestedType
, uint32_t* payloadSize
) const
91 assert(((long)this & 0x3) == 0);
92 if ( payloadSize
!= nullptr )
94 const TypedBytes
* end
= next(this);
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
;
107 //////////////////////////// Image ////////////////////////////////////////
109 const Image::Flags
& Image::getFlags() const
111 return *(Flags
*)((uint8_t*)this + 2*sizeof(TypedBytes
));
114 bool Image::isInvalid() const
116 return getFlags().isInvalid
;
119 size_t Image::size() const
121 return sizeof(TypedBytes
) + this->payloadLength
;
124 ImageNum
Image::imageNum() const
126 return getFlags().imageNum
;
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
132 const Flags
& flags
= getFlags();
133 if ( flags
.imageNum
== num
)
135 if ( !flags
.isDylib
)
137 if ( flags
.inDyldCache
)
139 ImageNum cacheImageNum
;
140 if ( isOverrideOfDyldCacheImage(cacheImageNum
) )
141 return (cacheImageNum
== num
);
145 uint32_t Image::maxLoadCount() const
147 return getFlags().maxLoadCount
;
150 bool Image::isBundle() const
152 return getFlags().isBundle
;
155 bool Image::isDylib() const
157 return getFlags().isDylib
;
160 bool Image::isExecutable() const
162 return getFlags().isExecutable
;
165 bool Image::hasObjC() const
167 return getFlags().hasObjC
;
170 bool Image::is64() const
172 return getFlags().is64
;
175 bool Image::hasWeakDefs() const
177 return getFlags().hasWeakDefs
;
180 bool Image::mayHavePlusLoads() const
182 return getFlags().mayHavePlusLoads
;
185 bool Image::neverUnload() const
187 return getFlags().neverUnload
;
190 bool Image::overridableDylib() const
192 return getFlags().overridableDylib
;
195 bool Image::inDyldCache() const
197 return getFlags().inDyldCache
;
200 const char* Image::path() const
202 // might be multiple pathWithHash enties, first is canonical name
203 const PathAndHash
* result
= (PathAndHash
*)findAttributePayload(Type::pathWithHash
);
204 assert(result
&& "Image missing pathWithHash");
208 const char* Image::leafName() const
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
) {
221 bool Image::hasFileModTimeAndInode(uint64_t& inode
, uint64_t& mTime
) const
224 const FileInfo
* info
= (FileInfo
*)(findAttributePayload(Type::fileInodeAndTime
, &size
));
225 if ( info
!= nullptr ) {
226 assert(size
== sizeof(FileInfo
));
228 mTime
= info
->modTime
;
234 bool Image::hasCdHash(uint8_t cdHash
[20]) const
237 const uint8_t* bytes
= (uint8_t*)(findAttributePayload(Type::cdHash
, &size
));
238 if ( bytes
!= nullptr ) {
240 memcpy(cdHash
, bytes
, 20);
246 bool Image::getUuid(uuid_t uuid
) const
249 const uint8_t* bytes
= (uint8_t*)(findAttributePayload(Type::uuid
, &size
));
250 if ( bytes
== nullptr )
253 memcpy(uuid
, bytes
, 16);
257 bool Image::hasCodeSignature(uint32_t& sigFileOffset
, uint32_t& sigSize
) const
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
;
270 bool Image::isFairPlayEncrypted(uint32_t& textOffset
, uint32_t& size
) const
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();
283 const Array
<Image::LinkedImage
> Image::dependentsArray() const
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
);
292 void Image::forEachDependentImage(void (^handler
)(uint32_t dependentIndex
, LinkKind kind
, ImageNum imageNum
, bool& stop
)) const
295 const LinkedImage
* dependents
= (LinkedImage
*)findAttributePayload(Type::dependents
, &size
);
296 assert((size
% sizeof(LinkedImage
)) == 0);
297 const uint32_t count
= size
/ sizeof(LinkedImage
);
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
) )
305 handler(i
, kind
, imageNum
, stop
);
309 ImageNum
Image::dependentImageNum(uint32_t depIndex
) const
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();
320 uint32_t Image::hashFunction(const char* str
)
323 for (const char* s
=str
; *s
!= '\0'; ++s
)
328 void Image::forEachAlias(void (^handler
)(const char* aliasPath
, bool& stop
)) const
330 __block
bool foundFirst
= false;
331 forEachAttribute(^(const TypedBytes
* typedBytes
, bool& stopLoop
) {
332 if ( (Type
)(typedBytes
->type
) != Type::pathWithHash
)
335 const PathAndHash
* aliasInfo
= (PathAndHash
*)typedBytes
->payload();
336 handler(aliasInfo
->path
, stopLoop
);
344 bool Image::hasPathWithHash(const char* path
, uint32_t hash
) const
346 __block
bool found
= false;
347 forEachAttribute(^(const TypedBytes
* typedBytes
, bool& stop
) {
348 if ( (Type
)(typedBytes
->type
) != Type::pathWithHash
)
350 const PathAndHash
* pathInfo
= (PathAndHash
*)typedBytes
->payload();
351 if ( (pathInfo
->hash
== hash
) && (strcmp(path
, pathInfo
->path
) == 0) ) {
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
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 ) {
376 vmOffset
-= (uint64_t)seg
->vmPageCount
* pageSz
;
378 // walk each segment and call handler
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
);
389 fileOffset
+= fileSize
;
393 uint32_t Image::pageSize() const
395 if ( getFlags().has16KBpages
)
401 uint32_t Image::cacheOffset() const
404 const DyldCacheSegment
* segments
= (DyldCacheSegment
*)findAttributePayload(Type::cacheSegment
, &size
);
405 assert(segments
!= nullptr);
406 assert((size
% sizeof(DyldCacheSegment
)) == 0);
407 return segments
[0].cacheOffset
;
410 void Image::forEachCacheSegment(void (^handler
)(uint32_t segIndex
, uint64_t vmOffset
, uint64_t vmSize
, uint8_t permissions
, bool& stop
)) const
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
);
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
);
428 uint64_t Image::textSize() const
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
) {
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) {
448 bool Image::containsAddress(const void* addr
, const void* imageLoadAddress
, uint8_t* permsResult
) const
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
) ) {
458 *permsResult
= permissions
;
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
) ) {
468 *permsResult
= permissions
;
476 uint64_t Image::vmSizeToMap() const
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();
485 uint64_t Image::sliceOffsetInFile() const
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;
494 void Image::forEachInitializer(const void* imageLoadAddress
, void (^handler
)(const void* initializer
)) const
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
);
509 bool Image::hasInitializers() const
512 return ( findAttributePayload(Type::initOffsets
, &size
) != nullptr );
515 void Image::forEachDOF(const void* imageLoadAddress
, void (^handler
)(const void* dofSection
)) const
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
);
530 void Image::forEachPatchableExport(void (^handler
)(uint32_t cacheOffsetOfImpl
, const char* exportName
)) const
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
]));
539 void Image::forEachPatchableUseOfExport(uint32_t cacheOffsetOfImpl
, void (^handler
)(PatchableExport::PatchLocation patchLocation
)) const
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
)
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
)
553 uint32_t Image::patchableExportCount() const
555 __block
uint32_t count
= 0;
556 forEachAttributePayload(Type::cachePatchInfo
, ^(const void* payload
, uint32_t size
, bool& stop
) {
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
566 const uint32_t pointerSize
= is64() ? 8 : 4;
567 uint64_t curRebaseOffset
= 0;
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
578 curRebaseOffset
+= rebasePat
.repeatCount
* rebasePat
.skipCount
;
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
;
588 curRebaseOffset
+= pointerSize
* rebasePat
.skipCount
;
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
));
609 const Array
<Image::ResolvedSymbolTarget
> targetsArray
= chainedTargets();
610 for (uint64_t start
: chainedStarts()) {
611 chainedFixupsStart(start
, targetsArray
, stop
);
617 void Image::forEachChainedFixup(void* imageLoadAddress
, uint64_t imageOffsetChainStart
, void (^callback
)(uint64_t* fixUpLoc
, ChainedFixupPointerOnDisk fixupInfo
, bool& stop
))
620 uint64_t* fixupLoc
= (uint64_t*)((uint8_t*)imageLoadAddress
+ imageOffsetChainStart
);
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
;
632 void Image::forEachTextReloc(void (^rebase
)(uint32_t imageOffsetToRebase
, bool& stop
),
633 void (^bind
)(uint32_t imageOffsetToBind
, ResolvedSymbolTarget bindTarget
, bool& stop
)) const
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
);
643 bind(curOffset
, pat
.target
, stop
);
644 curOffset
+= pat
.skipCount
;
649 const Array
<Image::RebasePattern
> Image::rebaseFixups() const
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
);
657 const Array
<Image::BindPattern
> Image::bindFixups() const
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
);
665 const Array
<uint64_t> Image::chainedStarts() const
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
);
673 const Array
<Image::ResolvedSymbolTarget
> Image::chainedTargets() const
676 ResolvedSymbolTarget
* targetsContent
= (ResolvedSymbolTarget
*)findAttributePayload(Type::chainedFixupsTargets
, &size
);
677 uint32_t count
= size
/sizeof(ResolvedSymbolTarget
);
678 return Array
<ResolvedSymbolTarget
>(targetsContent
, count
, count
);
681 const Array
<Image::TextFixupPattern
> Image::textFixups() const
684 TextFixupPattern
* fixupsContent
= (TextFixupPattern
*)findAttributePayload(Type::textFixups
, &fixupsSize
);
685 uint32_t count
= fixupsSize
/sizeof(TextFixupPattern
);
686 return Array
<TextFixupPattern
>(fixupsContent
, count
, count
);
689 bool Image::isOverrideOfDyldCacheImage(ImageNum
& imageNum
) const
692 const uint32_t* content
= (uint32_t*)findAttributePayload(Type::imageOverride
, &size
);
693 if ( content
!= nullptr ) {
694 assert(size
== sizeof(uint32_t));
701 void Image::forEachImageToInitBefore(void (^handler
)(ImageNum imageToInit
, bool& stop
)) const
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
);
709 for (uint32_t i
=0; (i
< count
) && !stop
; ++i
) {
710 handler(initBefores
[i
], stop
);
715 const char* Image::PatchableExport::PatchLocation::keyName() const
717 return MachOLoaded::ChainedFixupPointerOnDisk::keyName(this->key
);
720 Image::PatchableExport::PatchLocation::PatchLocation(size_t cacheOff
, uint64_t ad
)
721 : cacheOffset(cacheOff
), addend(ad
), authenticated(0), usesAddressDiversity(0), key(0), discriminator(0)
723 int64_t signedAddend
= (int64_t)ad
;
724 assert(((signedAddend
<< 52) >> 52) == signedAddend
);
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
)
730 int64_t signedAddend
= (int64_t)ad
;
731 assert(((signedAddend
<< 52) >> 52) == signedAddend
);
734 //////////////////////////// ImageArray ////////////////////////////////////////
736 size_t ImageArray::size() const
738 return sizeof(TypedBytes
) + this->payloadLength
;
741 size_t ImageArray::startImageNum() const
743 return firstImageNum
;
746 uint32_t ImageArray::imageCount() const
751 void ImageArray::forEachImage(void (^callback
)(const Image
* image
, bool& stop
)) const
754 for (uint32_t i
=0; i
< count
&& !stop
; ++i
) {
755 const Image
* image
= (Image
*)((uint8_t*)payload() + offsets
[i
]);
756 callback(image
, stop
);
762 bool ImageArray::hasPath(const char* path
, ImageNum
& num
) const
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();
776 const Image
* ImageArray::imageForNum(ImageNum num
) const
778 if ( num
< firstImageNum
)
781 uint32_t index
= num
- firstImageNum
;
782 if ( index
>= count
)
785 return (Image
*)((uint8_t*)payload() + offsets
[index
]);
788 const Image
* ImageArray::findImage(const Array
<const ImageArray
*> imagesArrays
, ImageNum imageNum
)
790 for (const ImageArray
* ia
: imagesArrays
) {
791 if ( const Image
* result
= ia
->imageForNum(imageNum
) )
797 //////////////////////////// Closure ////////////////////////////////////////
799 size_t Closure::size() const
801 return sizeof(TypedBytes
) + this->payloadLength
;
804 const ImageArray
* Closure::images() const
806 __block
const TypedBytes
* result
= nullptr;
807 forEachAttribute(^(const TypedBytes
* typedBytes
, bool& stop
) {
808 if ( (Type
)(typedBytes
->type
) == Type::imageArray
) {
814 return (ImageArray
*)result
;
817 ImageNum
Closure::topImage() const
820 const ImageNum
* top
= (ImageNum
*)findAttributePayload(Type::topImage
, &size
);
821 assert(top
!= nullptr);
822 assert(size
== sizeof(ImageNum
));
826 void Closure::forEachPatchEntry(void (^handler
)(const PatchEntry
& entry
)) const
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
)
837 void Closure::deallocate() const
839 ::vm_deallocate(mach_task_self(), (long)this, size());
842 //////////////////////////// LaunchClosure ////////////////////////////////////////
844 void LaunchClosure::forEachMustBeMissingFile(void (^handler
)(const char* path
, bool& stop
)) const
847 const char* paths
= (const char*)findAttributePayload(Type::missingFiles
, &size
);
849 for (const char* s
=paths
; s
< &paths
[size
]; ++s
) {
858 bool LaunchClosure::builtAgainstDyldCache(uuid_t cacheUUID
) const
861 const uint8_t* uuidBytes
= (uint8_t*)findAttributePayload(Type::dyldCacheUUID
, &size
);
862 if ( uuidBytes
== nullptr )
864 assert(size
== sizeof(uuid_t
));
865 memcpy(cacheUUID
, uuidBytes
, sizeof(uuid_t
));
869 const char* LaunchClosure::bootUUID() const
872 return (char*)findAttributePayload(Type::bootUUID
, &size
);
875 void LaunchClosure::forEachEnvVar(void (^handler
)(const char* keyEqualValue
, bool& stop
)) const
877 forEachAttributePayload(Type::envVar
, ^(const void* payload
, uint32_t size
, bool& stop
) {
878 handler((char*)payload
, stop
);
882 ImageNum
LaunchClosure::libSystemImageNum() const
885 const ImageNum
* num
= (ImageNum
*)findAttributePayload(Type::libSystemNum
, &size
);
886 assert(num
!= nullptr);
887 assert(size
== sizeof(ImageNum
));
891 void LaunchClosure::libDyldEntry(Image::ResolvedSymbolTarget
& loc
) const
894 const Image::ResolvedSymbolTarget
* data
= (Image::ResolvedSymbolTarget
*)findAttributePayload(Type::libDyldEntry
, &size
);
895 assert(data
!= nullptr);
896 assert(size
== sizeof(Image::ResolvedSymbolTarget
));
900 bool LaunchClosure::mainEntry(Image::ResolvedSymbolTarget
& mainLoc
) const
903 const Image::ResolvedSymbolTarget
* data
= (Image::ResolvedSymbolTarget
*)findAttributePayload(Type::mainEntry
, &size
);
904 if ( data
== nullptr )
906 assert(size
== sizeof(Image::ResolvedSymbolTarget
));
911 bool LaunchClosure::startEntry(Image::ResolvedSymbolTarget
& startLoc
) const
914 const Image::ResolvedSymbolTarget
* data
= (Image::ResolvedSymbolTarget
*)findAttributePayload(Type::startEntry
, &size
);
915 if ( data
== nullptr )
917 assert(size
== sizeof(Image::ResolvedSymbolTarget
));
922 const LaunchClosure::Flags
& LaunchClosure::getFlags() const
925 const Flags
* flags
= (Flags
*)findAttributePayload(Type::closureFlags
, &size
);
926 assert(flags
!= nullptr && "Closure missing Flags");
930 uint32_t LaunchClosure::initialLoadCount() const
932 return getFlags().initImageCount
;
935 bool LaunchClosure::usedAtPaths() const
937 return getFlags().usedAtPaths
;
940 bool LaunchClosure::usedFallbackPaths() const
942 return getFlags().usedFallbackPaths
;
945 void LaunchClosure::forEachInterposingTuple(void (^handler
)(const InterposingTuple
& tuple
, bool& stop
)) const
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
);
959 } // namespace closure