Loading...
common/ProcessAtlas.cpp dyld-1122.1 dyld-1330
--- dyld/dyld-1122.1/common/ProcessAtlas.cpp
+++ dyld/dyld-1330/common/ProcessAtlas.cpp
@@ -26,6 +26,7 @@
 
 #if !TARGET_OS_EXCLAVEKIT
 
+#include <span>
 #include <atomic>
 #include <cstring>
 #include <Block.h>
@@ -49,24 +50,27 @@
 #include "dyld_process_info_internal.h" // For dyld_all_image_infos_{32,64}
 
 #include "Defines.h"
+#include "Header.h"
 #include "DyldSharedCache.h"
-#include "MachOFile.h"
 #include "PVLEInt64.h"
-#include "MachOFile.h"
 #include "MachOLoaded.h"
 #include "ProcessAtlas.h"
-#include "Utils.h"
+#include "Utilities.h"
+#include "SafeVMPrimitives.h"
 
 #include "CRC32c.h"
 #include "UUID.h"
+#include "Bitmap.h"
 
 using lsl::CRC32c;
 using lsl::Allocator;
 using lsl::emitPVLEUInt64;
 using lsl::readPVLEUInt64;
+using lsl::Bitmap;
 
 using dyld3::FatFile;
-using dyld3::MachOFile;
+
+using mach_o::Header;
 // TODO: forEach shared cache needs to filter out subcaches and skip them
 
 // The allocations made by a snapshot need to last for the life of a spanshot. In libdyld that is under the caller control
@@ -76,8 +80,10 @@
 #if BUILDING_DYLD
 #define _transactionalAllocator _ephemeralAllocator
 #else
-#define _transactionalAllocator Allocator::defaultAllocator()
+#define _transactionalAllocator MemoryManager::memoryManager().defaultAllocator()
 #endif
+
+#define BLEND_KERN_RETURN_LOCATION(kr, loc) (kr) = ((kr & 0x00ffffff) | loc<<24);
 
 namespace {
 static const size_t kCachePeekSize = 0x4000;
@@ -96,7 +102,7 @@
 
 static void getCacheInfo(const dyld_cache_header *cache, uint64_t &headerSize, bool& splitCache) {
     // If we have sub caches, then the cache header itself tells us how much space we need to cover all caches
-    if ( cache->mappingOffset >= __offsetof(dyld_cache_header, subCacheArrayCount) ) {
+    if ( cache->mappingOffset >= offsetof(dyld_cache_header, subCacheArrayCount) ) {
         // New style cache
         headerSize = cache->subCacheArrayOffset + (sizeof(dyld_subcache_entry)*cache->subCacheArrayCount);
         splitCache = true;
@@ -121,56 +127,6 @@
 
 namespace dyld4 {
 namespace Atlas {
-
-Bitmap::Bitmap(Allocator& allocator, size_t size)
-    : _size(size), _bitmap(UniquePtr<std::byte>((std::byte*)allocator.malloc((size+7)/8))) {}
-
-Bitmap::Bitmap(Allocator& allocator, std::span<std::byte>& data) {
-    _size = (size_t)readPVLEUInt64(data);
-    const size_t byteSize = (_size+7)/8;
-    _bitmap = UniquePtr<std::byte>((std::byte*)allocator.malloc(byteSize));
-    _bitmap.withUnsafe([&](std::byte* bitmap) {
-        std::copy(&data[0], &data[byteSize], &bitmap[0]);
-    });
-    data = data.last(data.size()-byteSize);
-}
-
-Bitmap::Bitmap(Bitmap&& other) {
-    swap(other);
-}
-
-Bitmap& Bitmap::operator=(Bitmap&& other) {
-    swap(other);
-    return *this;
-}
-
-void Bitmap::setBit(size_t bit) {
-    contract(bit < _size);
-    _bitmap.withUnsafe([&](std::byte* bitmap) {
-        std::byte* byte = &bitmap[bit/8];
-        (*byte) |= (std::byte)(1<<(bit%8));
-    });
-}
-
-void Bitmap::emit(Vector<std::byte>& data) const {
-    emitPVLEUInt64(_size, data);
-    const size_t byteSize = (_size+7)/8;
-    _bitmap.withUnsafe([&](std::byte* bitmap) {
-        std::copy(&bitmap[0], &bitmap[byteSize], std::back_inserter(data));
-    });
-}
-
-size_t Bitmap::size() const {
-    return _size;
-}
-
-bool Bitmap::checkBit(size_t bit) const {
-    contract(bit < _size);
-    return ((std::byte)0 != _bitmap.withUnsafe([&](std::byte* bitmap) {
-        std::byte* byte = &bitmap[bit/8];
-        return ((*byte) & (std::byte)(1<<(bit%8)));
-    }));
-}
 
 #pragma mark -
 #pragma mark Mappers
@@ -209,7 +165,7 @@
 #endif
 }
 
-SharedPtr<Mapper> Mapper::mapperForSharedCache(Allocator& _ephemeralAllocator, FileRecord& file, const void* baseAddress) {
+SharedPtr<Mapper> Mapper::mapperForSharedCache(Allocator& _ephemeralAllocator, FileRecord& file, SafePointer baseAddress) {
     bool        useLocalCache   = false;
     size_t      length          = 0;
     uint64_t    slide     = 0;
@@ -247,7 +203,7 @@
     }
     if (!baseAddress) {
         // No base address passed in, treat as unslid
-        baseAddress = (void*)onDiskCacheHeader->sharedRegionStart;
+        baseAddress = onDiskCacheHeader->sharedRegionStart;
     }
     slide = (uint64_t)baseAddress-(uint64_t)onDiskCacheHeader->sharedRegionStart;
     uint64_t headerSize = 0;
@@ -295,7 +251,7 @@
         auto subCaches = (dyld_subcache_entry*)&onDiskHeaderBytes[onDiskCacheHeader->subCacheArrayOffset];
         for (auto i = 0; i < onDiskCacheHeader->subCacheArrayCount; ++i) {
             char subCachePath[PATH_MAX];
-            if (onDiskCacheHeader->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType)) {
+            if (onDiskCacheHeader->mappingOffset <= offsetof(dyld_cache_header, cacheSubType)) {
                 snprintf(&subCachePath[0], sizeof(subCachePath), "%s.%u", file.getPath(), i+1);
             } else {
                 char basePath[PATH_MAX];
@@ -321,7 +277,7 @@
 
             auto onDiskSubcacheUUID = UUID(subCache->uuid);
             uint8_t uuidBuf[16];
-            if (onDiskCacheHeader->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType))  {
+            if (onDiskCacheHeader->mappingOffset <= offsetof(dyld_cache_header, cacheSubType))  {
                 auto subCacheArray = (dyld_subcache_entry_v1*)&onDiskHeaderBytes[onDiskCacheHeader->subCacheArrayOffset];
                 memcpy(uuidBuf, subCacheArray[i].uuid, 16);
             } else {
@@ -405,7 +361,7 @@
     return { _transactionalAllocator.makeShared<Mapper>(_transactionalAllocator, mappings), baseAddress };
 }
 
-SharedPtr<Mapper> Mapper::mapperForMachO(Allocator& _ephemeralAllocator, FileRecord& file, const UUID& uuid, const void* baseAddress) {
+SharedPtr<Mapper> Mapper::mapperForMachO(Allocator& _ephemeralAllocator, FileRecord& file, const UUID& uuid, const SafePointer baseAddress) {
     const char* filePath = file.getPath();
     // open filePath
     int fd = dyld3::open(filePath, O_RDONLY, 0);
@@ -421,21 +377,21 @@
     }
 
     // mmap whole file temporarily
-    void* tempMapping = ::mmap(nullptr, (size_t)sb.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+    void* tempMapping = ::mmap(nullptr, (size_t)sb.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE | MAP_RESILIENT_CODESIGN, fd, 0);
     if ( tempMapping == MAP_FAILED ) {
         ::close(fd);
         return nullptr;
     }
 
     // if fat file, pick matching slice
-    __block const MachOFile*    mf         = nullptr;
+    __block const Header*    mf         = nullptr;
     const FatFile*              ff         = FatFile::isFatFile(tempMapping);
     __block uint64_t            fileOffset = 0;
     if (ff) {
         uint64_t                fileLength = sb.st_size;
         Diagnostics             diag;
         ff->forEachSlice(diag, fileLength, ^(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void *sliceStart, uint64_t sliceSize, bool &stop) {
-            auto slice = (MachOFile*)sliceStart;
+            auto slice = (Header*)sliceStart;
             uuid_t sliceUUIDRaw;
             slice->getUuid(sliceUUIDRaw);
             auto sliceUUID = UUID(sliceUUIDRaw);
@@ -449,7 +405,7 @@
         diag.clearError();
     }
     if (!mf) {
-        auto slice =  MachOFile::isMachO(tempMapping);
+        auto slice =  Header::isMachO({(uint8_t*)tempMapping, (size_t)sb.st_size});
         if (slice) {
             uuid_t sliceUUID;
             slice->getUuid(sliceUUID);
@@ -465,16 +421,16 @@
     }
     __block Vector<Mapper::Mapping> mappings(_transactionalAllocator);
     __block uint64_t slide = 0;
-    mf->forEachSegment(^(const MachOFile::SegmentInfo &info, bool &stop) {
-        if (strncmp(info.segName, "__TEXT", 16) == 0) {
-            slide = (uint64_t)baseAddress - info.vmAddr;
+    mf->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
+        if ( info.segmentName == "__TEXT" ) {
+            slide = (uint64_t)baseAddress - info.vmaddr;
         }
 //        fprintf(stderr, "Mapping\n");
 //        fprintf(stderr, "fd\tAddress\tFile Offset\tSize\n");
 //        fprintf(stderr, "%u\t0x%llx\t0x%llx\t%llu\n", fd, info.vmAddr + slide, info.fileOffset + fileOffset, info.vmSize);
         mappings.emplace_back((Mapper::Mapping) {
-            .address = info.vmAddr + slide,
-            .size = info.vmSize,
+            .address = info.vmaddr + slide,
+            .size = info.vmsize,
             .offset = info.fileOffset + fileOffset,
             .fd = fd
         });
@@ -502,46 +458,46 @@
     }
 }
 
-std::pair<void*,bool> Mapper::map(const void* addr, uint64_t size) const {
+std::pair<SafePointer,bool> Mapper::map(const SafePointer addr, uint64_t size) const {
     if (_flatMapping) {
         uint64_t offset = (uint64_t)addr-(uint64_t)baseAddress();
-        return {(void*)((uintptr_t)_flatMapping+offset),false};
+        return {(uint64_t)((uintptr_t)_flatMapping+offset),false};
     }
     if (_mappings.size() == 0) {
         // No mappings means we are an identity mapper
-        return { (void*)addr, false };
+        return { addr, false };
     }
     for (const auto& mapping : _mappings) {
         if (((uint64_t)addr >= mapping.address) && ((uint64_t)addr < (mapping.address + mapping.size))) {
             if (mapping.fd == -1) {
-                return {(void*)(((uint64_t)addr-mapping.address)+mapping.offset), false};
+                return {(((uint64_t)addr-mapping.address)+mapping.offset), false};
             }
             assert(((uint64_t)addr + size) <= mapping.address + mapping.size);
-            off_t offset = (off_t)addr - mapping.address + mapping.offset;
+            uint64_t offset = (uint64_t)addr - mapping.address + mapping.offset;
             // Handle unaligned mmap
             void* newMapping = nullptr;
             size_t extraBytes = 0;
-            off_t roundedOffset = offset & (-1*PAGE_SIZE);
+            uint64_t roundedOffset = offset & (-1*PAGE_SIZE);
             extraBytes = (size_t)offset - (size_t)roundedOffset;
             newMapping = mmap(nullptr, (size_t)size+extraBytes, PROT_READ, MAP_FILE | MAP_PRIVATE, mapping.fd, roundedOffset);
-            if (newMapping == (void*)-1) {
+            if (newMapping == MAP_FAILED) {
 //                fprintf(stderr, "mmap failed: %s (%d)\n", strerror(errno), errno);
-                return {(void*)1, false};
-            }
-            return {(void*)((uintptr_t)newMapping+extraBytes),true};
-        }
-    }
-    return {(void*)-1, false};
-}
-
-void Mapper::unmap(const void* addr, uint64_t size) const {
-    void* roundedAddr = (void*)((intptr_t)addr & (-1*PAGE_SIZE));
-    size_t extraBytes = (uintptr_t)addr - (uintptr_t)roundedAddr;
+                return { SafePointer(), false};
+            }
+            return {(uint64_t)((uintptr_t)newMapping+extraBytes),true};
+        }
+    }
+    return {SafePointer(), false};
+}
+
+void Mapper::unmap(const SafePointer addr, uint64_t size) const {
+    void* roundedAddr = (void*)((intptr_t)(uint64_t)addr & (-1*PAGE_SIZE));
+    size_t extraBytes = (uintptr_t)(uint64_t)addr - (uintptr_t)roundedAddr;
     munmap(roundedAddr, (size_t)size+extraBytes);
 }
 
-const void* Mapper::baseAddress() const {
-    return (const void*)_mappings[0].address;
+const SafePointer Mapper::baseAddress() const {
+    return _mappings[0].address;
 }
 
 const uint64_t Mapper::size() const {
@@ -589,25 +545,25 @@
 
 #if BUILDING_DYLD
 Image::Image(RuntimeState* state, Allocator& ephemeralAllocator, SharedPtr<Mapper>& mapper, const Loader* ldr)
-    :   _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _rebasedAddress((void*)ldr->loadAddress(*state)) {
+    :   _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _rebasedAddress((uint64_t)ldr->loadAddress(*state)) {
         auto fileID = ldr->fileID(*state);
         if (fileID.inode() &&  fileID.device()) {
             _file = state->fileManager.fileRecordForFileID(ldr->fileID(*state));
             if ( _file.volume().empty() ) {
-                _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path());
+                _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path(*state));
             }
         } else {
-            _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path());
+            _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path(*state));
         }
     }
 #endif
-Image::Image(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, const struct mach_header* mh)
-    : _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper), _rebasedAddress((void*)mh) {}
-Image::Image(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, const struct mach_header* mh, const UUID& uuid)
-    :  _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper), _uuid(uuid), _rebasedAddress((void*)mh) {}
-
-Image::Image(Allocator& ephemeralAllocator, SharedPtr<Mapper>& mapper, void* baseAddress, uint64_t cacheSlide, SharedCache* sharedCache)
-    : _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _sharedCacheSlide(cacheSlide), _rebasedAddress((void*)((uint64_t)baseAddress+cacheSlide)), _sharedCache(sharedCache) {}
+Image::Image(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, const SafePointer mh)
+    : _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper), _rebasedAddress(mh) {}
+Image::Image(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, const SafePointer mh, const UUID& uuid)
+    :  _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper), _uuid(uuid), _rebasedAddress(mh) {}
+
+Image::Image(Allocator& ephemeralAllocator, SharedPtr<Mapper>& mapper, SafePointer baseAddress, uint64_t cacheSlide, SharedCache* sharedCache)
+    : _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _sharedCacheSlide(cacheSlide), _rebasedAddress(((uint64_t)baseAddress+cacheSlide)), _sharedCache(sharedCache) {}
 
 Image::Image(Image&& other) : _ephemeralAllocator(other._ephemeralAllocator) {
     swap(other);
@@ -644,7 +600,7 @@
         return nullptr;
     }
     if (!_ml) {
-        void* slidML = (void*)rebasedAddress();
+        SafePointer slidML = rebasedAddress();
         // Note, using 4k here as we might be an arm64e process inspecting an x86_64 image, which uses 4k pages
         if (!_mapper && !_mapperFailed) {
             _mapper = Mapper::mapperForMachO(_transactionalAllocator, _file, _uuid, _rebasedAddress);
@@ -654,6 +610,10 @@
             return nullptr;
         }
         _ml = _mapper->map<MachOLoaded>(slidML, 4096);
+        if (!_ml) {
+           _mapperFailed = true;
+           return nullptr;
+        }
         size_t size = _ml->sizeofcmds;
         if ( _ml->magic == MH_MAGIC_64 ) {
             size += sizeof(mach_header_64);
@@ -662,6 +622,10 @@
         }
         if (size > 4096) {
             _ml = _mapper->map<MachOLoaded>(slidML, size);
+            if (!_ml) {
+               _mapperFailed = true;
+               return nullptr;
+            }
         }
     }
     // This is a bit of a mess. With compact info this will be unified, but for now we use a lot of hacky abstactions here to deal with
@@ -672,7 +636,7 @@
 const UUID& Image::uuid() const {
     if (!_uuidLoaded) {
         uuid_t fileUUID;
-        const MachOLoaded* mh = ml();
+        const Header* mh = (Header*)ml();
         if (mh && mh->hasMachOMagic()) {
             if (mh->getUuid(fileUUID))
                 _uuid = UUID(fileUUID);
@@ -682,7 +646,7 @@
     return _uuid;
 }
 
-uint64_t Image::rebasedAddress() const {
+SafePointer Image::rebasedAddress() const {
     return (uint64_t)_rebasedAddress;
 }
 
@@ -690,7 +654,7 @@
 const char* Image::installname() const {
     if (!_installnameLoaded) {
         if (ml()) {
-            _installname = ml()->installName();
+            _installname = ((const Header*)ml())->installName();
         }
         _installnameLoaded = true;
     }
@@ -710,7 +674,7 @@
 }
 
 uint64_t Image::sharedCacheVMOffset() const {
-    return (uint64_t)_rebasedAddress - sharedCache()->rebasedAddress();
+    return (uint64_t)_rebasedAddress - (uint64_t)sharedCache()->rebasedAddress();
 }
 
 uint32_t Image::pointerSize() {
@@ -720,34 +684,34 @@
 
 bool Image::forEachSegment(void (^block)(const char* segmentName, uint64_t vmAddr, uint64_t vmSize, int perm)) {
     if (!ml()) { return false; }
-    __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
-    ml()->forEachSegment(^(const MachOLoaded::SegmentInfo &info, bool &stop) {
+    __block uint64_t slide = (uint64_t)_rebasedAddress - ((const Header*)ml())->preferredLoadAddress();
+    ((const Header*)ml())->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
         uint64_t vmAddr = 0x0;
         if ( _sharedCacheSlide.has_value() ) {
-            vmAddr = info.vmAddr + _sharedCacheSlide.value();
+            vmAddr = info.vmaddr + _sharedCacheSlide.value();
         } else {
             if ( ml()->isMainExecutable() ) {
-                if ( strncmp(info.segName, "__PAGEZERO", 10) == 0 )
+                if ( info.segmentName.starts_with("__PAGEZERO") )
                     return;
             }
-            vmAddr = info.vmAddr + slide;
-        }
-        block(info.segName, vmAddr, info.vmSize, info.protections);
+            vmAddr = info.vmaddr + slide;
+        }
+        block(info.segmentName.data(), vmAddr, info.vmsize, info.initProt);
     });
     return true;
 }
 
 bool Image::forEachSection(void (^block)(const char* segmentName, const char* sectionName, uint64_t vmAddr, uint64_t vmSize)) {
     if (!ml()) { return false; }
-    __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
-    ml()->forEachSection(^(const MachOLoaded::SectionInfo &info, bool malformedSectionRange, bool &stop) {
+    __block uint64_t slide = (uint64_t)_rebasedAddress - ((const Header*)ml())->preferredLoadAddress();
+    ((const Header*)ml())->forEachSection(^(const Header::SectionInfo &info, bool &stop) {
         uint64_t sectAddr = 0x0;
         if ( _sharedCacheSlide.has_value() ) {
-            sectAddr = info.sectAddr + _sharedCacheSlide.value();
+            sectAddr = info.address + _sharedCacheSlide.value();
         } else {
-            sectAddr = info.sectAddr + slide;
-        }
-        block(info.segInfo.segName, info.sectName, sectAddr, info.sectSize);
+            sectAddr = info.address + slide;
+        }
+        block(info.segmentName.data(), info.sectionName.data(), sectAddr, info.size);
     });
     return true;
 }
@@ -755,23 +719,23 @@
 bool Image::contentForSegment(const char* segmentName, void (^contentReader)(const void* content, uint64_t vmAddr, uint64_t vmSize)) {
     if (!ml()) { return false; }
     __block bool result = false;
-    __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
-    ml()->forEachSegment(^(const MachOLoaded::SegmentInfo &info, bool &stop) {
-        if (strcmp(segmentName, info.segName) != 0) { return; }
+    __block uint64_t slide = (uint64_t)_rebasedAddress - ((const Header*)ml())->preferredLoadAddress();
+    ((const Header*)ml())->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
+        if ( segmentName != info.segmentName ) { return; }
         uint64_t vmAddr = 0;
         if ( _sharedCacheSlide.has_value() ) {
-            vmAddr = info.vmAddr + _sharedCacheSlide.value();
+            vmAddr = info.vmaddr + _sharedCacheSlide.value();
         } else {
             if ( ml()->isMainExecutable() ) {
-                if ( strncmp(info.segName, "__PAGEZERO", 10) == 0 )
+                if ( info.segmentName.starts_with("__PAGEZERO") )
                     return;
             }
-            vmAddr = info.vmAddr + slide;
-        }
-
-        if (info.vmSize) {
-            auto content = _mapper->map<uint8_t>((void*)(vmAddr), info.vmSize);
-            contentReader((void*)&*content, vmAddr, info.vmSize);
+            vmAddr = info.vmaddr + slide;
+        }
+
+        if (info.vmsize) {
+            auto content = _mapper->map<uint8_t>(vmAddr, info.vmsize);
+            contentReader((void*)&*content, vmAddr, info.vmsize);
         } else {
             contentReader(nullptr, vmAddr, 0);
         }
@@ -784,19 +748,19 @@
 bool Image::contentForSection(const char* segmentName, const char* sectionName,
                               void (^contentReader)(const void* content, uint64_t vmAddr, uint64_t vmSize)) {
     __block bool result = false;
-    __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
-    ml()->forEachSection(^(const MachOLoaded::SectionInfo &info, bool malformedRange, bool &stop) {
-        if (strcmp(segmentName, info.segInfo.segName) != 0) { return; }
-        if (strcmp(sectionName, info.sectName) != 0) { return; }
+    __block uint64_t slide = (uint64_t)_rebasedAddress - ((const Header*)ml())->preferredLoadAddress();
+    ((const Header*)ml())->forEachSection(^(const Header::SectionInfo &info, bool &stop) {
+        if ( segmentName != info.segmentName ) { return; }
+        if ( sectionName != info.sectionName ) { return; }
         uint64_t sectAddr = 0;
         if ( _sharedCacheSlide.has_value() ) {
-            sectAddr = info.sectAddr + _sharedCacheSlide.value();
+            sectAddr = info.address + _sharedCacheSlide.value();
         } else {
-            sectAddr = info.sectAddr + slide;
-        }
-        if (info.sectSize) {
-            auto content = _mapper->map<uint8_t>((void*)(sectAddr), info.sectSize);
-            contentReader((void*)&*content, sectAddr, info.sectSize);
+            sectAddr = info.address + slide;
+        }
+        if (info.size) {
+            auto content = _mapper->map<uint8_t>(sectAddr, info.size);
+            contentReader((void*)&*content, sectAddr, info.size);
         } else {
             contentReader(nullptr, sectAddr, 0);
         }
@@ -811,12 +775,12 @@
 
 SharedCacheLocals::SharedCacheLocals(SharedPtr<Mapper>& M, bool use64BitDylibOffsets)
     : _mapper(M), _use64BitDylibOffsets(use64BitDylibOffsets) {
-    auto header = _mapper->map<dyld_cache_header>((void*)0, sizeof(dyld_cache_header));
+    auto header = _mapper->map<dyld_cache_header>(0ULL, sizeof(dyld_cache_header));
 
     // Map in the whole locals buffer.
     // TODO: Once we have the symbols in their own file, simplify this to just map the whole file
     // and not do the header and locals separately
-    _locals = _mapper->map<uint8_t>((void*)header->localSymbolsOffset, header->localSymbolsSize);
+    _locals = _mapper->map<uint8_t>(header->localSymbolsOffset, header->localSymbolsSize);
 }
 
 const dyld_cache_local_symbols_info* SharedCacheLocals::localInfo() const {
@@ -835,7 +799,7 @@
                                 uint64_t rebasedAddress, bool splitCache)
 {
     // If we have sub caches, then the cache header itself tells us how much space we need to cover all caches
-    if (header->mappingOffset >= __offsetof(dyld_cache_header, subCacheArrayCount) ) {
+    if (header->mappingOffset >= offsetof(dyld_cache_header, subCacheArrayCount) ) {
         return header->sharedRegionSize;
     } else {
         auto headerBytes = (uint8_t*)&*header;
@@ -849,19 +813,19 @@
         if (splitCache) {
             for (auto i = 0; i < header->subCacheArrayCount; ++i) {
                 uint64_t subCacheOffset = 0;
-                if (header->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType) ) {
+                if (header->mappingOffset <= offsetof(dyld_cache_header, cacheSubType) ) {
                     auto subCaches = (dyld_subcache_entry_v1*)&headerBytes[header->subCacheArrayOffset];
                     subCacheOffset = subCaches[i].cacheVMOffset;
                 } else {
                     auto subCaches = (dyld_subcache_entry*)&headerBytes[header->subCacheArrayOffset];
                     subCacheOffset = subCaches[i].cacheVMOffset;
                 }
-                auto subCacheHeader = mapper->map<dyld_cache_header>((void*)(subCacheOffset + rebasedAddress), PAGE_SIZE);
+                auto subCacheHeader = mapper->map<dyld_cache_header>(subCacheOffset + rebasedAddress, PAGE_SIZE);
                 uint64_t subCacheHeaderSize = 0;
                 bool splitCacheUnused;
                 getCacheInfo(&*subCacheHeader, subCacheHeaderSize, splitCacheUnused);
                 if (subCacheHeaderSize > PAGE_SIZE) {
-                    subCacheHeader = mapper->map<dyld_cache_header>((void*)(subCacheOffset + rebasedAddress), subCacheHeaderSize);
+                    subCacheHeader = mapper->map<dyld_cache_header>(subCacheOffset + rebasedAddress, subCacheHeaderSize);
                 }
                 auto subCacheHeaderBytes = (uint8_t*)&*subCacheHeader;
                 auto subCacheMappings = (dyld_cache_mapping_and_slide_info*)&subCacheHeaderBytes[subCacheHeader->mappingWithSlideOffset];
@@ -876,20 +840,20 @@
     }
 }
 
-SharedCache::SharedCache(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, uint64_t rebasedAddress, bool P)
+SharedCache::SharedCache(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, SafePointer rebasedAddress, bool P)
     : _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper),  _rebasedAddress(rebasedAddress), _private(P)
 {
     assert(_mapper);
-    _header = _mapper->map<dyld_cache_header>((void*)_rebasedAddress, PAGE_SIZE);
+    _header = _mapper->map<dyld_cache_header>(_rebasedAddress, PAGE_SIZE);
     uint64_t headerSize = 0;
     bool splitCache = false;
     getCacheInfo(&*_header, headerSize, splitCache);
     if (headerSize > PAGE_SIZE) {
-        _header = _mapper->map<dyld_cache_header>((void*)_rebasedAddress, headerSize);
+        _header = _mapper->map<dyld_cache_header>(_rebasedAddress, headerSize);
     }
     _uuid = UUID(&_header->uuid[0]);
-    _slide = _rebasedAddress -  _header->sharedRegionStart;
-    _size = cacheMappedSize(_header, _mapper, rebasedAddress, splitCache);
+    _slide = (uint64_t)_rebasedAddress -  _header->sharedRegionStart;
+    _size = cacheMappedSize(_header, _mapper, (uint64_t)rebasedAddress, splitCache);
 }
 
 
@@ -903,6 +867,7 @@
         "/private/preboot/Cryptexes/OS/System/DriverKit/System/Library/dyld/",
         "/System/Cryptexes/OS/System/Library/Caches/com.apple.dyld/",
         "/System/Cryptexes/OS/System/Library/dyld/",
+        "/System/Cryptexes/ExclaveOS/System/ExclaveKit/System/Library/dyld/",
         "/System/Volumes/Preboot/Cryptexes/Incoming/OS/System/Library/dyld/",
         "/System/Volumes/Preboot/Cryptexes/Incoming/OS/System/DriverKit/System/Library/dyld/",
         "/private/preboot/Cryptexes/Incoming/OS/System/Library/Caches/com.apple.dyld/",
@@ -911,6 +876,7 @@
         "/System/Cryptexes/Incoming/OS/System/Library/dyld/",
         "/System/Library/Caches/com.apple.dyld/",
         "/System/DriverKit/System/Library/dyld/",
+        "/System/ExclaveKit/System/Library/dyld/",
         "/System/Library/dyld/"
     };
 
@@ -977,7 +943,7 @@
 
 UniquePtr<SharedCache> SharedCache::createForFileRecord(Allocator& _ephemeralAllocator, FileRecord&& file) {
     auto uuid = UUID();
-    auto fileMapper = Mapper::mapperForSharedCache(_ephemeralAllocator, file, 0);
+    auto fileMapper = Mapper::mapperForSharedCache(_ephemeralAllocator, file, 0ULL);
     if (!fileMapper) { return nullptr; }
     return _transactionalAllocator.makeUnique<SharedCache>(_ephemeralAllocator, std::move(file), fileMapper, (uint64_t)fileMapper->baseAddress(), true);
 }
@@ -987,7 +953,7 @@
     return _uuid;
 }
 
-uint64_t SharedCache::rebasedAddress() const {
+SafePointer SharedCache::rebasedAddress() const {
     return _rebasedAddress;
 }
 
@@ -1010,7 +976,7 @@
     if (splitCache) {
         auto headerBytes = (std::byte*)&*_header;
         char subCachePath[PATH_MAX];
-        if (_header->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType)) {
+        if (_header->mappingOffset <= offsetof(dyld_cache_header, cacheSubType)) {
             for (auto i = 0; i < _header->subCacheArrayCount; ++i) {
                 snprintf(&subCachePath[0], sizeof(subCachePath), "%s.%u", _file.getPath(), i+1);
                 block(subCachePath);
@@ -1022,7 +988,7 @@
                 block(subCachePath);
             }
         }
-        if ( (_header->mappingOffset >= __offsetof(dyld_cache_header, symbolFileUUID)) && !uuid_is_null(_header->symbolFileUUID) ) {
+        if ( (_header->mappingOffset >= offsetof(dyld_cache_header, symbolFileUUID)) && !uuid_is_null(_header->symbolFileUUID) ) {
             strlcpy(&subCachePath[0], _file.getPath(), PATH_MAX);
             // On new caches, the locals come from a new subCache file
             if (strstr(subCachePath, ".development") != nullptr) {
@@ -1046,7 +1012,7 @@
     auto headerBytes = (uint8_t*)&*_header;
     auto images = std::span((const dyld_cache_image_text_info*)&headerBytes[_header->imagesTextOffset], (size_t)_header->imagesTextCount);
     for (auto i : images) {
-        auto image = Image(_ephemeralAllocator, _mapper,  (void*)(i.loadAddress), _slide, this);
+        auto image = Image(_ephemeralAllocator, _mapper, i.loadAddress, _slide, this);
         block(&image);
     }
 }
@@ -1054,7 +1020,7 @@
 void SharedCache::withImageForIndex(uint32_t idx, void (^block)(Image* image)) {
     auto headerBytes = (uint8_t*)&*_header;
     auto images = std::span((const dyld_cache_image_text_info*)&headerBytes[_header->imagesTextOffset], (size_t)_header->imagesTextCount);
-    auto image = Image(_ephemeralAllocator, _mapper,  (void*)(images[idx].loadAddress), _slide, this);
+    auto image = Image(_ephemeralAllocator, _mapper, images[idx].loadAddress, _slide, this);
     block(&image);
 }
 
@@ -1065,7 +1031,7 @@
     // Where it is depends on the cache header
     char localSymbolsCachePath[PATH_MAX];
     strlcpy(&localSymbolsCachePath[0], _file.getPath(), PATH_MAX);
-    bool useSymbolsFile = (_header->mappingOffset >= __offsetof(dyld_cache_header, symbolFileUUID));
+    bool useSymbolsFile = (_header->mappingOffset >= offsetof(dyld_cache_header, symbolFileUUID));
     if ( useSymbolsFile ) {
         if ( uuid_is_null(_header->symbolFileUUID) )
             return nullptr;
@@ -1116,7 +1082,7 @@
     for(auto i = 0; i < _header->mappingCount; ++i) {
         //    _slide = _baseAddress -  _header->sharedRegionStart;
         auto mapping = (dyld_cache_mapping_info*)&subCacheHeaderBytes[subCacheHeader->mappingOffset+(i*sizeof(dyld_cache_mapping_info))];
-        auto mappingBytes = _mapper->map<uint8_t>((void*)(mapping->address - _slide), mapping->size);
+        auto mappingBytes = _mapper->map<uint8_t>(mapping->address - _slide, mapping->size);
         kern_return_t r = vm_copy(mach_task_self(), (vm_address_t)&*mappingBytes, (vm_size_t)mapping->size, (vm_address_t)(mappedSubCache+mapping->fileOffset));
         if ( r != KERN_SUCCESS ) {
             result = false;
@@ -1142,18 +1108,18 @@
     if (splitCache) {
         for (auto i = 0; i < _header->subCacheArrayCount; ++i) {
             uint64_t subCacheOffset = 0;
-            if (_header->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType) ) {
+            if (_header->mappingOffset <= offsetof(dyld_cache_header, cacheSubType) ) {
                 auto subCaches = (dyld_subcache_entry_v1*)&headerBytes[_header->subCacheArrayOffset];
                 subCacheOffset = subCaches[i].cacheVMOffset;
             } else {
                 auto subCaches = (dyld_subcache_entry*)&headerBytes[_header->subCacheArrayOffset];
                 subCacheOffset = subCaches[i].cacheVMOffset;
             }
-            auto subCacheHeader = _mapper->map<dyld_cache_header>((void*)(rebasedAddress() + subCacheOffset), PAGE_SIZE);
+            auto subCacheHeader = _mapper->map<dyld_cache_header>((uint64_t)rebasedAddress() + subCacheOffset, PAGE_SIZE);
             uint64_t subCacheHeaderSize = subCacheHeader->mappingOffset+subCacheHeader->mappingCount*sizeof(dyld_cache_mapping_info);
             getCacheInfo(&*_header, headerSize, splitCache);
             if (subCacheHeaderSize > PAGE_SIZE) {
-                subCacheHeader = _mapper->map<dyld_cache_header>((void*)(rebasedAddress() + subCacheOffset), subCacheHeaderSize);
+                subCacheHeader = _mapper->map<dyld_cache_header>((uint64_t)rebasedAddress() + subCacheOffset, subCacheHeaderSize);
             }
 //            printf("Subcache Offset: %lx\n", (uintptr_t)&headerBytes[subCacheOffset]);
 //            printf("subCacheHeader: %lx\n", (uintptr_t)&*subCacheHeader);
@@ -1229,6 +1195,8 @@
     pid_t   pid;
     *kr = pid_for_task(_task, &pid);
     if ( *kr != KERN_SUCCESS ) {
+        BLEND_KERN_RETURN_LOCATION(*kr, 0xea);
+        *kr |= 0xeb000000UL;
         return nullptr;
     }
 
@@ -1236,6 +1204,7 @@
     mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
     *kr = task_info(_task, MACH_TASK_BASIC_INFO, (task_info_t)&ti, &count);
     if ( *kr != KERN_SUCCESS ) {
+        BLEND_KERN_RETURN_LOCATION(*kr, 0xe9);
         return nullptr;
     }
 
@@ -1259,13 +1228,14 @@
             mach_vm_size_t readSize = 0;
             *kr = mach_vm_read_overwrite(_task, address, size, (mach_vm_address_t)&unsafeBytes[0], &readSize);
             if ( *kr != KERN_SUCCESS ) {
+                BLEND_KERN_RETURN_LOCATION(*kr, 0xe8);
                 return;
             }
-            auto mf = MachOFile::isMachO((const void*)unsafeBytes);
-            if (!mf) {
+            auto mh = Header::isMachO({(const uint8_t*)unsafeBytes, (size_t)readSize});
+            if (!mh) {
                 return;
             }
-            if ( mf->filetype == MH_EXECUTE ) {
+            if ( mh->isMainExecutable() ) {
                 int len = proc_regionfilename(pid, address, executablePath, PATH_MAX);
                 if ( len != 0 ) {
                     executablePath[len] = '\0';
@@ -1273,11 +1243,11 @@
                 SharedPtr<Mapper> mapper = nullptr;
                 auto file = _fileManager.fileRecordForPath(_transactionalAllocator, executablePath);
                 uuid_t rawUUID;
-                mf->getUuid(rawUUID);
+                mh->getUuid(rawUUID);
                 auto uuid = UUID(rawUUID);
-                result->addImage(Image(_transactionalAllocator, std::move(file), mapper, (const mach_header*)address, uuid));
+                result->addImage(Image(_transactionalAllocator, std::move(file), mapper, (uint64_t)address, uuid));
                 foundMainExecutable = true;
-            } else if ( mf->filetype == MH_DYLINKER ) {
+            } else if ( mh->isDylinker() ) {
                 int len = proc_regionfilename(pid, address, executablePath, PATH_MAX);
                 if ( len != 0 ) {
                     executablePath[len] = '\0';
@@ -1285,9 +1255,9 @@
                 SharedPtr<Mapper> mapper = nullptr;
                 auto file = _fileManager.fileRecordForPath(_transactionalAllocator, executablePath);
                 uuid_t rawUUID;
-                mf->getUuid(rawUUID);
+                mh->getUuid(rawUUID);
                 auto uuid = UUID(rawUUID);
-                result->addImage(Image(_transactionalAllocator, std::move(file), mapper, (const mach_header*)address, uuid));
+                result->addImage(Image(_transactionalAllocator, std::move(file), mapper, (uint64_t)address, uuid));
                 foundDyld = true;
             }
         });
@@ -1319,48 +1289,55 @@
     task_dyld_info_data_t task_dyld_info;
     *kr = task_info(_task, TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count);
     if ( *kr != KERN_SUCCESS ) {
+        BLEND_KERN_RETURN_LOCATION(*kr, 0xef);
         return nullptr;
     }
     //The kernel will return MACH_VM_MIN_ADDRESS for an executable that has not had dyld loaded
     if (task_dyld_info.all_image_info_addr == MACH_VM_MIN_ADDRESS) {
+        BLEND_KERN_RETURN_LOCATION(*kr, 0xee);
         return nullptr;
     }
-    uint8_t remoteBuffer[16*1024];
-    mach_vm_size_t readSize = 0;
+    uint64_t failedAddress = 0;
     while (1) {
         // Using mach_vm_read_overwrite because this is part of dyld. If the file is removed or the codesignature is invalid
         // then the system is broken beyond recovery anyway
-        *kr = mach_vm_read_overwrite(_task, task_dyld_info.all_image_info_addr, task_dyld_info.all_image_info_size,
-                                     (mach_vm_address_t)&remoteBuffer[0], &readSize);
+        auto taskInfoBuffer = SafeRemoteBuffer(_task, task_dyld_info.all_image_info_addr, task_dyld_info.all_image_info_size, kr);
         if (*kr != KERN_SUCCESS) {
+            BLEND_KERN_RETURN_LOCATION(*kr, 0xed);
             // If we cannot read the all image info this is game over
             return nullptr;
         }
         uint64_t compactInfoAddress;
         uint64_t compactInfoSize;
         if (task_dyld_info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_32 ) {
-            const dyld_all_image_infos_32* info = (const dyld_all_image_infos_32*)&remoteBuffer[0];
+            const dyld_all_image_infos_32* info = (const dyld_all_image_infos_32*)&taskInfoBuffer.data()[0];
             compactInfoAddress              = info->compact_dyld_image_info_addr;
             compactInfoSize                 = info->compact_dyld_image_info_size;
         } else {
-            const dyld_all_image_infos_64* info = (const dyld_all_image_infos_64*)&remoteBuffer[0];
+            const dyld_all_image_infos_64* info = (const dyld_all_image_infos_64*)&taskInfoBuffer.data()[0];
             compactInfoAddress              = info->compact_dyld_image_info_addr;
             compactInfoSize                 = info->compact_dyld_image_info_size;
         }
         if (compactInfoSize == 0) {
             return synthesizeSnapshot(kr);
         }
-        auto compactInfo = UniquePtr<std::byte>((std::byte*)_transactionalAllocator.malloc((size_t)compactInfoSize));
-        *kr = mach_vm_read_overwrite(_task, compactInfoAddress, compactInfoSize, (mach_vm_address_t)&*compactInfo, &readSize);
+        
+        auto compactInfoBuffer = SafeRemoteBuffer(_task, compactInfoAddress,compactInfoSize, kr);
         if (*kr != KERN_SUCCESS) {
+            BLEND_KERN_RETURN_LOCATION(*kr, 0xec);
+            if (compactInfoAddress == failedAddress) {
+                // We tried the same address twice and it failed both times, this is not a simple mutation issue, give up and reutrn an error
+                return nullptr;
+            }
+            failedAddress = compactInfoAddress;
             // The read failed, chances are the process mutated the compact info, retry
             continue;
         }
-        std::span<std::byte> data = std::span<std::byte>(&*compactInfo, (size_t)compactInfoSize);
-        UniquePtr<ProcessSnapshot> result = _transactionalAllocator.makeUnique<ProcessSnapshot>(_ephemeralAllocator, _fileManager, false, data);
+        UniquePtr<ProcessSnapshot> result = _transactionalAllocator.makeUnique<ProcessSnapshot>(_ephemeralAllocator, _fileManager, false, compactInfoBuffer.data());
         if (!result->valid()) {
             // Something blew up we don't know what
             *kr = KERN_FAILURE;
+            BLEND_KERN_RETURN_LOCATION(*kr, 0xeb);
             return nullptr;
         }
         return result;
@@ -1598,14 +1575,46 @@
     :   _ephemeralAllocator(ephemeralAllocator), _fileManager(fileManager), _images(_transactionalAllocator),
         _identityMapper(_transactionalAllocator.makeShared<Mapper>(_transactionalAllocator)), _useIdentityMapper(useIdentityMapper) {}
 
+#if BUILDING_LIBDYLD && !TARGET_OS_DRIVERKIT && !TARGET_OS_EXCLAVEKIT
+// This function is a private interface between libdyld and Dyld.framework and implemented in Swift
+// there is no header
+extern "C" const bool unwrapCompactInfo(void* _Nonnull buffer, uint64_t* _Nonnull size);
+#endif /* BUILDING_LIBDYLD && !TARGET_OS_DRIVERKIT && !TARGET_OS_EXCLAVEKIT */
+
 ProcessSnapshot::ProcessSnapshot(Allocator& ephemeralAllocator, FileManager& fileManager, bool useIdentityMapper, const std::span<std::byte> data)
     :   _ephemeralAllocator(ephemeralAllocator), _fileManager(fileManager), _images(_transactionalAllocator),
         _identityMapper(_transactionalAllocator.makeShared<Mapper>(_transactionalAllocator)), _useIdentityMapper(useIdentityMapper) {
         Serializer serializer(*this);
-        if (!serializer.deserialize(data)) {
+        bool deserializedSucceeed = serializer.deserialize(data);
+#if BUILDING_LIBDYLD && !TARGET_OS_DRIVERKIT && !TARGET_OS_EXCLAVEKIT
+        static dispatch_once_t onceToken;
+        static __typeof__(unwrapCompactInfo) *unwrapCompactInfoPtr = nullptr;
+        if (!deserializedSucceeed) {
+            // If we failed we try to load the unwrap function
+            dispatch_once(&onceToken, ^{
+                // We attempt a dlopen() here since the unwrapCompactInfo is not in the build yet, and this is a temporary compatibility hack
+                void* dyldFrameworkHandle = dlopen("/System/Library/PrivateFrameworks/Dyld.framework/Dyld", RTLD_NOW);
+                unwrapCompactInfoPtr = (__typeof__(unwrapCompactInfo)*)dlsym(dyldFrameworkHandle, "unwrapCompactInfo");
+            });
+        }
+        // Only try the fallback if we managed to load the unwrap function
+        if (unwrapCompactInfoPtr && !deserializedSucceeed) {
+            std::byte* unwrappedData = (std::byte*)_transactionalAllocator.malloc(data.size());
+            std::copy(data.begin(), data.end(), unwrappedData);
+            uint64_t unwrappedSize = data.size();
+            if (unwrapCompactInfoPtr((void*)unwrappedData, &unwrappedSize)) {
+                std::span<std::byte> unwrappedSpan = std::span<std::byte>(unwrappedData, (size_t)unwrappedSize);
+                deserializedSucceeed = serializer.deserialize(unwrappedSpan);
+            }
+            free((void*)unwrappedData);
+        }
+#endif /* BUILDING_LIBDYLD && !TARGET_OS_DRIVERKIT && !TARGET_OS_EXCLAVEKIT */
+        if (!deserializedSucceeed) {
             // Deerialization failed, reset the snapshot and mark invalid
             _images.clear();
-            _bitmap             = nullptr;
+            if (_bitmap) {
+                _bitmap->clear();
+            }
             _sharedCache        = nullptr;
             _platform           = 0;
             _initialImageCount  = 0;
@@ -1662,7 +1671,7 @@
     uint64_t address    = ~0ULL;
     auto i              = other._images.begin();
     if (i != other._images.end()) {
-        address = (*i)->rebasedAddress();
+        address = (uint64_t)(*i)->rebasedAddress();
     }
 
     for (auto& image : _images) {
@@ -1674,7 +1683,7 @@
                 address = ~0ULL;
                 break;
             }
-            address = (*i)->rebasedAddress();
+            address = (uint64_t)(*i)->rebasedAddress();
         }
         if (image->rebasedAddress() != address) {
             block(&*image);
@@ -1691,7 +1700,7 @@
 }
 
 #if BUILDING_DYLD
-void ProcessSnapshot::addImages(RuntimeState* state, const std::span<const Loader*>& loaders) {
+void ProcessSnapshot::addImages(RuntimeState* state, Vector<ConstAuthLoader>& loaders) {
     for (auto& ldr : loaders) {
         if (_sharedCache && ldr->dylibInDyldCache) {
             _bitmap->setBit(ldr->ref.index);
@@ -1721,7 +1730,7 @@
 
 void ProcessSnapshot::addSharedCacheImage(const struct mach_header* mh) {
     assert(mh->flags & MH_DYLIB_IN_CACHE);
-    auto header = (dyld_cache_header*)_sharedCache->rebasedAddress();
+    auto header = (dyld_cache_header*)(uint64_t)_sharedCache->rebasedAddress();
     auto headerBytes = (uint8_t*)header;
     auto slide = (uint64_t)header - header->sharedRegionStart;
     auto images = std::span((const dyld_cache_image_text_info*)&headerBytes[header->imagesTextOffset], (size_t)header->imagesTextCount);
@@ -1775,7 +1784,7 @@
         if (!name) {
             name = "<unknown>";
         }
-        fprintf(stderr, "0x%llx %s %s\n",  image->rebasedAddress(), uuidStr, name);
+        fprintf(stderr, "0x%llx %s %s\n",  (uint64_t)image->rebasedAddress(), uuidStr, name);
     });
 }
 
@@ -1888,22 +1897,37 @@
     }
 }
 
-void ProcessSnapshot::Serializer::readMappedFileInfo(std::span<std::byte>& data, uint64_t& rebasedAddress, UUID& uuid, FileRecord& file) {
-    uint64_t flags = readPVLEUInt64(data);
-    rebasedAddress = readPVLEUInt64(data);
+bool ProcessSnapshot::Serializer::readMappedFileInfo(std::span<std::byte>& data, uint64_t& rebasedAddress, UUID& uuid, FileRecord& file) {
+    uint64_t flags = 0;
+    if (!readPVLEUInt64(data, flags)
+        || !readPVLEUInt64(data, rebasedAddress)) {
+        return false;
+    }
     if (flags & kMappedFileFlagsHasUUID) {
+        if (data.size() < 16) {
+            return false;
+        }
         uuid = UUID(&data[0]);
         data = data.last(data.size()-16);
     }
     if (flags & kMappedFileFlagsHasFileID) {
-        uint64_t volumeIndex = readPVLEUInt64(data);
-        uint64_t objectID = readPVLEUInt64(data);
+        uint64_t volumeIndex = 0;
+        uint64_t objectID = 0;
+        if (!readPVLEUInt64(data, volumeIndex)
+            || !readPVLEUInt64(data, objectID)
+            || volumeIndex >= _volumeUUIDs.size()) {
+            return false;
+        }
         file = _fileManager.fileRecordForVolumeUUIDAndObjID(_volumeUUIDs[(size_t)volumeIndex], objectID);
     }
     if (flags & kMappedFileFlagsHasFilePath) {
-        uint64_t pathOffset = readPVLEUInt64(data);
+        uint64_t pathOffset = 0;
+        if (!readPVLEUInt64(data, pathOffset) || pathOffset >= _stringTableBuffer.size()) {
+            return false;
+        }
         file = _fileManager.fileRecordForPath(_ephemeralAllocator, &_stringTableBuffer[(size_t)pathOffset]);
     }
+    return true;
 }
 
 Vector<std::byte> ProcessSnapshot::Serializer::serialize() {
@@ -1975,16 +1999,18 @@
     emitPVLEUInt64(_stringTableBuffer.size(), result);
     std::copy((std::byte*)_stringTableBuffer.begin(), (std::byte*)_stringTableBuffer.end(), std::back_inserter(result));
     if (_processFlags & kProcessFlagsHasSharedCache) {
-        uint64_t address = _sharedCache->rebasedAddress()/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
+        uint64_t address = (uint64_t)_sharedCache->rebasedAddress()/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
         emitMappedFileInfo(address, _sharedCache->uuid(), _sharedCache->file(), result);
-        _bitmap->emit(result);
+        emitPVLEUInt64(_bitmap->size(), result);
+        if (_bitmap->size() > 0)
+            emit(_bitmap->bytes(), result);
     }
 
     emitPVLEUInt64(_images.size(), result);
     uint64_t lastAddress = 0;
     for (const auto& image : _images) {
-        uint64_t address = (image->rebasedAddress()-lastAddress)/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
-        lastAddress = image->rebasedAddress();
+        uint64_t address = ((uint64_t)image->rebasedAddress()-lastAddress)/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
+        lastAddress = (uint64_t)image->rebasedAddress();
         emitMappedFileInfo(address, image->uuid(), image->file(), result);
     }
     while(result.size()%16 != 0) {
@@ -1998,6 +2024,10 @@
 
 bool ProcessSnapshot::Serializer::deserialize(const std::span<std::byte> data) {
     auto i = data;
+    if (i.size() < 36) {
+        // Ensure data is at least large enough to read the header
+        return false;
+    }
     // Confirm magic
     _magic              = read<uint32_t>(i);
     _version            = read<uint32_t>(i);
@@ -2019,17 +2049,27 @@
     if (_crc32c != checksumer) {
         return false;
     }
-    _processFlags           = readPVLEUInt64(i);
-    _platform               = readPVLEUInt64(i);
-    _initialImageCount      = readPVLEUInt64(i);
-    _dyldState              = readPVLEUInt64(i);
-    auto volumeUUIDCount    = readPVLEUInt64(i);
+    uint64_t volumeUUIDCount = 0;
+    if (!readPVLEUInt64(i, _processFlags)
+        || !readPVLEUInt64(i, _platform)
+        || !readPVLEUInt64(i, _initialImageCount)
+        || !readPVLEUInt64(i, _dyldState)
+        || !readPVLEUInt64(i, volumeUUIDCount)) {
+        return false;
+    }
+    if (i.size() < volumeUUIDCount*16) {
+        return false;
+    }
     for (auto j = 0; j < volumeUUIDCount; ++j) {
         UUID volumeUUID(&i[j*16]);
         _volumeUUIDs.push_back(volumeUUID);
     }
     i = i.last((size_t)(i.size()-(16*volumeUUIDCount)));
-    auto stringTableSize    = readPVLEUInt64(i);
+    uint64_t stringTableSize = 0;
+    if (!readPVLEUInt64(i, stringTableSize)
+        || i.size() < stringTableSize) {
+        return false;
+    }
     _stringTableBuffer.reserve((size_t)stringTableSize);
     std::copy((uint8_t*)&i[0], (uint8_t*)&i[(size_t)stringTableSize], std::back_inserter(_stringTableBuffer));
     i = i.last((size_t)(i.size()-stringTableSize));
@@ -2038,8 +2078,9 @@
         uint64_t rebasedAddress;
         UUID uuid;
         FileRecord file;
-        readMappedFileInfo(i, rebasedAddress, uuid, file);
-        rebasedAddress = rebasedAddress * ((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
+        if ( !readMappedFileInfo(i, rebasedAddress, uuid, file) )
+            return false;
+        rebasedAddress = rebasedAddress * ((_processFlags & kProcessFlagsHas16kPages) ? kPageSize16K : kPageSize4K);
         SharedPtr<Mapper> mapper = nullptr;
         if (_processSnapshot._useIdentityMapper) {
             mapper = _processSnapshot.identityMapper();
@@ -2047,24 +2088,34 @@
 #if BUILDING_DYLD || BUILDING_UNIT_TESTS
             mapper = _transactionalAllocator.makeShared<Mapper>(_transactionalAllocator);
 #else
-            mapper = Mapper::mapperForSharedCache(_transactionalAllocator, file, (void*)rebasedAddress);
+            mapper = Mapper::mapperForSharedCache(_transactionalAllocator, file, rebasedAddress);
 #endif
         }
         if (!mapper) {
             return false;
         }
-
-        _sharedCache = _transactionalAllocator.makeUnique<SharedCache>(_ephemeralAllocator, std::move(file), mapper,
+        _sharedCache = _transactionalAllocator.makeUnique<SharedCache>(_transactionalAllocator, std::move(file), mapper,
                                                                        rebasedAddress, _processFlags & kProcessFlagsHasPrivateCache);
-        _bitmap = _transactionalAllocator.makeUnique<Bitmap>(_transactionalAllocator, i);
-    }
-    auto imageCount = readPVLEUInt64(i);
+        uint64_t encodedSize = 0;
+        if (!readPVLEUInt64(i, encodedSize)) {
+            return false;
+        }
+        _bitmap = _transactionalAllocator.makeUnique<Bitmap>(_transactionalAllocator, (size_t)encodedSize, i);
+        if (_bitmap->size() == 0) {
+            return false;
+        }
+    }
+    uint64_t imageCount = 0;
+    if (!readPVLEUInt64(i, imageCount)) {
+        return false;
+    }
     uint64_t lastAddress = 0;
     for (auto j = 0; j < imageCount; ++j) {
         uint64_t rebasedAddress;
         UUID uuid;
         FileRecord file;
-        readMappedFileInfo(i, rebasedAddress, uuid, file);
+        if ( !readMappedFileInfo(i, rebasedAddress, uuid, file) )
+            return false;
         rebasedAddress = (rebasedAddress * ((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096)) + lastAddress;
         lastAddress = rebasedAddress;
         SharedPtr<Mapper> mapper = nullptr;
@@ -2076,7 +2127,7 @@
             mapper = _transactionalAllocator.makeShared<Mapper>(_transactionalAllocator);
         }
 #endif
-        auto image = Image(_ephemeralAllocator, std::move(file), mapper, (const struct mach_header*)rebasedAddress, uuid);
+        auto image = Image(_transactionalAllocator, std::move(file), mapper, (uint64_t)rebasedAddress, uuid);
         _images.insert(_transactionalAllocator.makeUnique<Image>(std::move(image)));
     }
     return true;
@@ -2085,3 +2136,4 @@
 };
 };
 #endif // !TARGET_OS_EXCLAVEKIT
+