Loading...
--- dyld/dyld-1165.3/common/DyldSharedCache.cpp
+++ dyld/dyld-960/common/DyldSharedCache.cpp
@@ -22,9 +22,6 @@
* @APPLE_LICENSE_HEADER_END@
*/
-#include <TargetConditionals.h>
-
-#if !TARGET_OS_EXCLAVEKIT
#include <dirent.h>
#include <sys/errno.h>
@@ -45,7 +42,7 @@
#include <vector>
#include <unordered_map>
#include <unordered_set>
-// #include "SharedCacheBuilder.h"
+#include "SharedCacheBuilder.h"
#include "FileUtils.h"
#endif
@@ -64,18 +61,14 @@
#include <sstream>
#endif
-using dyld3::MachOFile;
-using dyld3::MachOLoaded;
-using dyld3::MachOAnalyzer;
using dyld4::PrebuiltLoader;
using dyld4::PrebuiltLoaderSet;
-
#if (BUILDING_LIBDYLD || BUILDING_DYLD)
VIS_HIDDEN bool gEnableSharedCacheDataConst = false;
#endif
-#if 0 // BUILDING_CACHE_BUILDER
+#if BUILDING_CACHE_BUILDER
DyldSharedCache::CreateResults DyldSharedCache::create(const CreateOptions& options,
const dyld3::closure::FileSystem& fileSystem,
const std::vector<MappedMachO>& dylibsToCache,
@@ -237,17 +230,10 @@
return (const T)(addr + slide);
}
-const char* DyldSharedCache::getCacheTypeName(uint64_t cacheType) {
- switch ( cacheType ) {
- case kDyldSharedCacheTypeDevelopment:
- return "development";
- case kDyldSharedCacheTypeProduction:
- return "production";
- case kDyldSharedCacheTypeUniversal:
- return "universal";
- default:
- return "unknown";
- }
+uint64_t DyldSharedCache::getCodeSignAddress() const
+{
+ auto mappings = (const dyld_cache_mapping_info*)((uint8_t*)this + header.mappingOffset);
+ return mappings[header.mappingCount-1].address + mappings[header.mappingCount-1].size;
}
void DyldSharedCache::forEachRegion(void (^handler)(const void* content, uint64_t vmAddr, uint64_t size,
@@ -282,40 +268,6 @@
}
}
-const char* DyldSharedCache::mappingName(uint32_t maxProt, uint64_t flags)
-{
- const char* mappingName = "";
- if ( maxProt & VM_PROT_EXECUTE ) {
- if ( flags & DYLD_CACHE_MAPPING_TEXT_STUBS ) {
- mappingName = "__TEXT_STUBS";
- } else {
- mappingName = "__TEXT";
- }
- } else if ( maxProt & VM_PROT_WRITE ) {
- if ( flags & DYLD_CACHE_MAPPING_AUTH_DATA ) {
- if ( flags & DYLD_CACHE_MAPPING_DIRTY_DATA )
- mappingName = "__AUTH_DIRTY";
- else if ( flags & DYLD_CACHE_MAPPING_CONST_DATA )
- mappingName = "__AUTH_CONST";
- else
- mappingName = "__AUTH";
- } else {
- if ( flags & DYLD_CACHE_MAPPING_DIRTY_DATA )
- mappingName = "__DATA_DIRTY";
- else if ( flags & DYLD_CACHE_MAPPING_CONST_DATA )
- mappingName = "__DATA_CONST";
- else
- mappingName = "__DATA";
- }
- }
- else if ( maxProt & VM_PROT_READ ) {
- mappingName = "__LINKEDIT";
- } else {
- mappingName = "*unknown*";
- }
- return mappingName;
-}
-
void DyldSharedCache::forEachRange(void (^handler)(const char* mappingName,
uint64_t unslidVMAddr, uint64_t vmSize,
uint32_t cacheFileIndex, uint64_t fileOffset,
@@ -327,7 +279,31 @@
forEachCache(^(const DyldSharedCache *cache, bool& stopCache) {
cache->forEachRegion(^(const void *content, uint64_t unslidVMAddr, uint64_t size,
uint32_t initProt, uint32_t maxProt, uint64_t flags, bool& stopRegion) {
- const char* mappingName = DyldSharedCache::mappingName(maxProt, flags);
+ const char* mappingName = "";
+ if ( maxProt & VM_PROT_EXECUTE ) {
+ mappingName = "__TEXT";
+ } else if ( maxProt & VM_PROT_WRITE ) {
+ if ( flags & DYLD_CACHE_MAPPING_AUTH_DATA ) {
+ if ( flags & DYLD_CACHE_MAPPING_DIRTY_DATA )
+ mappingName = "__AUTH_DIRTY";
+ else if ( flags & DYLD_CACHE_MAPPING_CONST_DATA )
+ mappingName = "__AUTH_CONST";
+ else
+ mappingName = "__AUTH";
+ } else {
+ if ( flags & DYLD_CACHE_MAPPING_DIRTY_DATA )
+ mappingName = "__DATA_DIRTY";
+ else if ( flags & DYLD_CACHE_MAPPING_CONST_DATA )
+ mappingName = "__DATA_CONST";
+ else
+ mappingName = "__DATA";
+ }
+ }
+ else if ( maxProt & VM_PROT_READ ) {
+ mappingName = "__LINKEDIT";
+ } else {
+ mappingName = "*unknown*";
+ }
uint64_t fileOffset = (uint8_t*)content - (uint8_t*)cache;
bool stop = false;
handler(mappingName, unslidVMAddr, size, cacheFileIndex, fileOffset, initProt, maxProt, stop);
@@ -360,8 +336,9 @@
if ( header.mappingOffset <= __offsetof(dyld_cache_header, subCacheArrayCount) )
return;
+ const dyld_subcache_entry* subCaches = (const dyld_subcache_entry*)((uint8_t*)this + header.subCacheArrayOffset);
for (uint32_t i = 0; i != header.subCacheArrayCount; ++i) {
- const DyldSharedCache* cache = (const DyldSharedCache*)((uintptr_t)this + this->getSubCacheVmOffset(i));
+ const DyldSharedCache* cache = (const DyldSharedCache*)((uint8_t*)this + subCaches[i].cacheVMOffset);
handler(cache, stop);
if ( stop )
return;
@@ -376,44 +353,7 @@
return header.subCacheArrayCount;
}
-int32_t DyldSharedCache::getSubCacheIndex(const void* addr) const
-{
- __block int32_t index = 0;
- __block bool found = false;
- this->forEachCache(^(const DyldSharedCache *cache, bool &stopCache) {
- bool readOnly = false;
- if ( cache->inCache(addr, sizeof(uint64_t), readOnly) ) {
- stopCache = true;
- found = true;
- return;
- }
- index++;
- });
- int32_t result = found ? index : -1;
- return result;
-}
-
-void DyldSharedCache::getSubCacheUuid(uint8_t index, uint8_t uuid[]) const {
- if (header.mappingOffset <= __offsetof(dyld_cache_header, cacheSubType) ) {
- const dyld_subcache_entry_v1* subCacheEntries = (dyld_subcache_entry_v1*)((uintptr_t)this + header.subCacheArrayOffset);
- memcpy(uuid, subCacheEntries[index].uuid, 16);
- } else {
- const dyld_subcache_entry* subCacheEntries = (dyld_subcache_entry*)((uintptr_t)this + header.subCacheArrayOffset);
- memcpy(uuid, subCacheEntries[index].uuid, 16);
- }
-}
-
-uint64_t DyldSharedCache::getSubCacheVmOffset(uint8_t index) const {
- if (header.mappingOffset <= __offsetof(dyld_cache_header, cacheSubType) ) {
- const dyld_subcache_entry_v1* subCacheEntries = (dyld_subcache_entry_v1*)((uintptr_t)this + header.subCacheArrayOffset);
- return subCacheEntries[index].cacheVMOffset;
- } else {
- const dyld_subcache_entry* subCacheEntries = (dyld_subcache_entry*)((uintptr_t)this + header.subCacheArrayOffset);
- return subCacheEntries[index].cacheVMOffset;
- }
-}
-
-bool DyldSharedCache::inCache(const void* addr, size_t length, bool& immutable) const
+bool DyldSharedCache::inCache(const void* addr, size_t length, bool& readOnly) const
{
// quick out if before start of cache
if ( addr < this )
@@ -423,19 +363,22 @@
uintptr_t slide = (uintptr_t)this - (uintptr_t)(mappings[0].address);
uintptr_t unslidStart = (uintptr_t)addr - slide;
- // walk cache ranges
- __block bool found = false;
- auto inRange = ^(const char* mappingName, uint64_t unslidVMAddr, uint64_t vmSize, uint32_t cacheFileIndex,
- uint64_t fileOffset, uint32_t initProt, uint32_t maxProt, bool& stopRange) {
- if ( (unslidVMAddr <= unslidStart) && ((unslidStart+length) < (unslidVMAddr+vmSize)) ) {
- found = true;
- immutable = ((maxProt & VM_PROT_WRITE) == 0);
- stopRange = true;
- }
- };
- this->forEachRange(inRange, nullptr);
-
- return found;
+ // quick out if after end of cache
+ const dyld_cache_mapping_info* lastMapping = &mappings[header.mappingCount - 1];
+ if ( unslidStart > (lastMapping->address + lastMapping->size) )
+ return false;
+
+ // walk cache regions
+ const dyld_cache_mapping_info* mappingsEnd = &mappings[header.mappingCount];
+ uintptr_t unslidEnd = unslidStart + length;
+ for (const dyld_cache_mapping_info* m=mappings; m < mappingsEnd; ++m) {
+ if ( (unslidStart >= m->address) && (unslidEnd < (m->address+m->size)) ) {
+ readOnly = ((m->initProt & VM_PROT_WRITE) == 0);
+ return true;
+ }
+ }
+
+ return false;
}
bool DyldSharedCache::isAlias(const char* path) const {
@@ -548,7 +491,7 @@
// check for cache without local symbols info
if (!this->hasLocalSymbolsInfo())
return nullptr;
- const auto localInfo = (dyld_cache_local_symbols_info*)((uintptr_t)this + header.localSymbolsOffset);
+ const auto localInfo = (dyld_cache_local_symbols_info*)((uint8_t*)this + header.localSymbolsOffset);
return getLocalNlistEntries(localInfo);
}
@@ -557,7 +500,7 @@
// check for cache without local symbols info
if (!this->hasLocalSymbolsInfo())
return 0;
- const auto localInfo = (dyld_cache_local_symbols_info*)((uintptr_t)this + header.localSymbolsOffset);
+ const auto localInfo = (dyld_cache_local_symbols_info*)((uint8_t*)this + header.localSymbolsOffset);
return localInfo->nlistCount;
}
@@ -571,7 +514,7 @@
// check for cache without local symbols info
if (!this->hasLocalSymbolsInfo())
return nullptr;
- const auto localInfo = (dyld_cache_local_symbols_info*)((uintptr_t)this + header.localSymbolsOffset);
+ const auto localInfo = (dyld_cache_local_symbols_info*)((uint8_t*)this + header.localSymbolsOffset);
return getLocalStrings(localInfo);
}
@@ -580,7 +523,7 @@
// check for cache without local symbols info
if (!this->hasLocalSymbolsInfo())
return 0;
- const auto localInfo = (dyld_cache_local_symbols_info*)((uintptr_t)this + header.localSymbolsOffset);
+ const auto localInfo = (dyld_cache_local_symbols_info*)((uint8_t*)this + header.localSymbolsOffset);
return localInfo->stringsSize;
}
@@ -590,7 +533,7 @@
const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)this + header.mappingOffset);
uint32_t dyldCacheImageIndex;
if ( hasImagePath(dylibPath, dyldCacheImageIndex) )
- return (dyld3::MachOFile*)((uintptr_t)this + dylibs[dyldCacheImageIndex].address - mappings[0].address);
+ return (dyld3::MachOFile*)((uint8_t*)this + dylibs[dyldCacheImageIndex].address - mappings[0].address);
return nullptr;
}
@@ -599,7 +542,7 @@
// check for cache without local symbols info
if (!this->hasLocalSymbolsInfo())
return;
- const auto localInfo = (dyld_cache_local_symbols_info*)((uintptr_t)this + header.localSymbolsOffset);
+ const auto localInfo = (dyld_cache_local_symbols_info*)((uint8_t*)this + header.localSymbolsOffset);
if ( header.mappingOffset >= __offsetof(dyld_cache_header, symbolFileUUID) ) {
// On new caches, the dylibOffset is 64-bits, and is a VM offset
@@ -624,17 +567,10 @@
const mach_header* DyldSharedCache::getIndexedImageEntry(uint32_t index, uint64_t& mTime, uint64_t& inode) const
{
const dyld_cache_image_info* dylibs = images();
- const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((uintptr_t)this + header.mappingOffset);
+ const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)this + header.mappingOffset);
mTime = dylibs[index].modTime;
inode = dylibs[index].inode;
- return (mach_header*)((uintptr_t)this + dylibs[index].address - mappings[0].address);
-}
-
-const mach_header* DyldSharedCache::getIndexedImageEntry(uint32_t index) const
-{
- uint64_t mTime = 0;
- uint64_t inode = 0;
- return this->getIndexedImageEntry(index, mTime, inode);
+ return (mach_header*)((uint8_t*)this + dylibs[index].address - mappings[0].address);
}
@@ -710,9 +646,9 @@
else if ( maxProt == VM_PROT_READ )
prot = "RO";
if ( size > 1024*1024 )
- snprintf(lineBuffer, sizeof(lineBuffer), "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot, size/(1024*1024), vmAddr, vmAddr+size);
+ sprintf(lineBuffer, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot, size/(1024*1024), vmAddr, vmAddr+size);
else
- snprintf(lineBuffer, sizeof(lineBuffer), "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot, size/1024, vmAddr, vmAddr+size);
+ sprintf(lineBuffer, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot, size/1024, vmAddr, vmAddr+size);
result += lineBuffer;
});
@@ -724,7 +660,7 @@
const dyld3::MachOFile* mf = (dyld3::MachOFile*)mh;
mf->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& info, bool& stop) {
char lineBuffer[256];
- snprintf(lineBuffer, sizeof(lineBuffer), "\t%16s 0x%08llX -> 0x%08llX\n", info.segName, info.vmAddr, info.vmAddr+info.vmSize);
+ sprintf(lineBuffer, "\t%16s 0x%08llX -> 0x%08llX\n", info.segName, info.vmAddr, info.vmAddr+info.vmSize);
result += lineBuffer;
});
result += "\n";
@@ -822,15 +758,41 @@
return false;
}
+bool DyldSharedCache::isOverridablePath(const char* dylibPath) const
+{
+ // all dylibs in customer dyld cache cannot be overridden except libdispatch.dylib
+ if ( header.cacheType == kDyldSharedCacheTypeProduction ) {
+ return (strcmp(dylibPath, "/usr/lib/system/libdispatch.dylib") == 0);
+ }
+ // in dev caches we can override all paths
+ return true;
+}
+
+bool DyldSharedCache::hasNonOverridablePath(const char* dylibPath) const
+{
+ // all dylibs in customer dyld cache cannot be overridden except libdispatch.dylib
+ bool pathIsInDyldCacheWhichCannotBeOverridden = false;
+ if ( header.cacheType == kDyldSharedCacheTypeProduction ) {
+ uint32_t imageIndex;
+ pathIsInDyldCacheWhichCannotBeOverridden = this->hasImagePath(dylibPath, imageIndex);
+ if ( pathIsInDyldCacheWhichCannotBeOverridden && isOverridablePath(dylibPath) )
+ pathIsInDyldCacheWhichCannotBeOverridden = false;
+ }
+ return pathIsInDyldCacheWhichCannotBeOverridden;
+}
+
intptr_t DyldSharedCache::slide() const
{
const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)this + header.mappingOffset);
return (intptr_t)this - (intptr_t)(mappings[0].address);
}
-const PrebuiltLoaderSet* DyldSharedCache::dylibsLoaderSet() const
+const PrebuiltLoader* DyldSharedCache::findPrebuiltLoader(const char* path) const
{
if ( header.mappingOffset < __offsetof(dyld_cache_header, programTrieSize) )
+ return nullptr;
+ uint32_t imageIndex;
+ if ( !this->hasImagePath(path, imageIndex) )
return nullptr;
const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)((char*)this + header.mappingOffset);
if ( mappings[0].fileOffset != 0 )
@@ -841,20 +803,7 @@
return nullptr;
uintptr_t slide = (uintptr_t)this - (uintptr_t)(mappings[0].address);
const PrebuiltLoaderSet* pbLoaderSet = (PrebuiltLoaderSet*)(this->header.dylibsPBLSetAddr + slide);
- return pbLoaderSet;
-}
-
-const PrebuiltLoader* DyldSharedCache::findPrebuiltLoader(const char* path) const
-{
- if ( header.mappingOffset < __offsetof(dyld_cache_header, programTrieSize) )
- return nullptr;
- uint32_t imageIndex;
- if ( !this->hasImagePath(path, imageIndex) )
- return nullptr;
- if ( const PrebuiltLoaderSet* pbLoaderSet = this->dylibsLoaderSet() )
- return pbLoaderSet->atIndex(imageIndex);
-
- return nullptr;
+ return pbLoaderSet->atIndex(imageIndex);
}
void DyldSharedCache::forEachLaunchLoaderSet(void (^handler)(const char* executableRuntimePath, const PrebuiltLoaderSet* pbls)) const
@@ -904,22 +853,17 @@
bool DyldSharedCache::hasLaunchLoaderSetWithCDHash(const char* cdHashString) const
{
- return (findLaunchLoaderSetWithCDHash(cdHashString) != nullptr);
-}
-
-const dyld4::PrebuiltLoaderSet* DyldSharedCache::findLaunchLoaderSetWithCDHash(const char* cdHashString) const
-{
if ( cdHashString == nullptr )
- return nullptr;
+ return false;
// Check source doesn't overflow buffer. strncat unfortunately isn't available
if ( strlen(cdHashString) >= 128 )
- return nullptr;
-
- char cdPath[140];
- strlcpy(cdPath, "/cdhash/", sizeof(cdPath));
- strlcat(cdPath, cdHashString, sizeof(cdPath));
- return findLaunchLoaderSet(cdPath);
+ return false;
+
+ char buffer[128] = { '\0' };
+ strcat(buffer, "/cdhash/");
+ strlcat(buffer, cdHashString, sizeof(buffer));
+ return findLaunchLoaderSet(buffer) != nullptr;
}
@@ -1057,11 +1001,6 @@
}
}
-const void* DyldSharedCache::patchTable() const
-{
- return getAddrField<const void*>(header.patchInfoAddr);
-}
-
uint32_t DyldSharedCache::patchInfoVersion() const {
if ( header.mappingOffset <= __offsetof(dyld_cache_header, swiftOptsSize) ) {
return 1;
@@ -1087,13 +1026,25 @@
return patchArray[imageIndex].patchExportsCount;
}
- // V2/V3 and newer structs
- PatchTable patchTable(this->patchTable(), header.patchInfoAddr);
- return patchTable.patchableExportCount(imageIndex);
-}
-
-void DyldSharedCache::forEachPatchableExport(uint32_t imageIndex, void (^handler)(uint32_t dylibVMOffsetOfImpl, const char* exportName,
- PatchKind patchKind)) const {
+ // V2 and newer structs
+ if ( patchVersion == 2 ) {
+ const dyld_cache_patch_info_v2* patchInfo = getAddrField<dyld_cache_patch_info_v2*>(header.patchInfoAddr);
+ const dyld_cache_image_patches_v2* patchArray = getAddrField<dyld_cache_image_patches_v2*>(patchInfo->patchTableArrayAddr);
+
+ // FIXME: This shouldn't be possible. The cache builder always adds 1 dyld_cache_image_patches_v2 per-image. But for now
+ // be conservative to match V1.
+ if (imageIndex > patchInfo->patchTableArrayCount)
+ return 0;
+
+ const dyld_cache_image_patches_v2& imagePatches = patchArray[imageIndex];
+ return imagePatches.patchExportsCount;
+ }
+
+ // Unknown version
+ assert(false);
+}
+
+void DyldSharedCache::forEachPatchableExport(uint32_t imageIndex, void (^handler)(uint32_t dylibVMOffsetOfImpl, const char* exportName)) const {
if ( header.patchInfoAddr == 0 )
return;
@@ -1127,22 +1078,43 @@
// Convert from a cache offset to an offset from the input image
uint32_t imageOffset = (uint32_t)((cacheUnslidAddress + patchExport.cacheOffsetOfImpl) - imageLoadAddress);
- handler(imageOffset, exportName, PatchKind::regular);
- }
-
- return;
- }
-
- // V2 newer structs
- PatchTable patchTable(this->patchTable(), header.patchInfoAddr);
- patchTable.forEachPatchableExport(imageIndex, handler);
-}
-
-#if BUILDING_SHARED_CACHE_UTIL
+ handler(imageOffset, exportName);
+ }
+
+ return;
+ }
+
+ // V2 and newer structs
+ if ( patchVersion == 2 ) {
+ const auto* patchInfo = getAddrField<dyld_cache_patch_info_v2*>(header.patchInfoAddr);
+ const auto* patchArray = getAddrField<dyld_cache_image_patches_v2*>(patchInfo->patchTableArrayAddr);
+ const auto* imageExports = getAddrField<dyld_cache_image_export_v2*>(patchInfo->patchImageExportsArrayAddr);
+ const char* exportNames = getAddrField<char*>(patchInfo->patchExportNamesAddr);
+
+ // FIXME: This shouldn't be possible. The cache builder always adds 1 dyld_cache_image_patches_v2 per-image. But for now
+ // be conservative to match V1.
+ if (imageIndex > patchInfo->patchTableArrayCount)
+ return;
+
+ const dyld_cache_image_patches_v2& imagePatches = patchArray[imageIndex];
+ // FIXME: This shouldn't be possible. We should catch this in the builder instead
+ if ( (imagePatches.patchExportsStartIndex + imagePatches.patchExportsCount) > patchInfo->patchImageExportsArrayCount )
+ return;
+
+ for (uint64_t exportIndex = 0; exportIndex != imagePatches.patchExportsCount; ++exportIndex) {
+ const dyld_cache_image_export_v2& imageExport = imageExports[imagePatches.patchExportsStartIndex + exportIndex];
+ const char* exportName = ( imageExport.exportNameOffset < patchInfo->patchExportNamesSize ) ? &exportNames[imageExport.exportNameOffset] : "";
+ handler(imageExport.dylibOffsetOfImpl, exportName);
+ }
+ return;
+ }
+
+ assert(false);
+}
+
void DyldSharedCache::forEachPatchableUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
void (^handler)(uint32_t userImageIndex, uint32_t userVMOffset,
- MachOLoaded::PointerMetaData pmd, uint64_t addend,
- bool isWeakImport)) const {
+ MachOLoaded::PointerMetaData pmd, uint64_t addend)) const {
if ( header.patchInfoAddr == 0 )
return;
@@ -1248,17 +1220,72 @@
pmd.key = patchLocation.key;
pmd.usesAddrDiversity = patchLocation.usesAddressDiversity;
- handler(userImageIndex, userVMOffset, pmd, patchLocation.getAddend(), false);
+ handler(userImageIndex, userVMOffset, pmd, patchLocation.getAddend());
}
}
return;
}
- // V2/V3 and newer structs
- PatchTable patchTable(this->patchTable(), header.patchInfoAddr);
- patchTable.forEachPatchableUseOfExport(imageIndex, dylibVMOffsetOfImpl, handler);
-}
-#endif
+ // V2 and newer structs
+ if ( patchVersion == 2 ) {
+ const auto* patchInfo = getAddrField<dyld_cache_patch_info_v2*>(header.patchInfoAddr);
+ const auto* patchArray = getAddrField<dyld_cache_image_patches_v2*>(patchInfo->patchTableArrayAddr);
+ const auto* imageExports = getAddrField<dyld_cache_image_export_v2*>(patchInfo->patchImageExportsArrayAddr);
+ const auto* clientArray = getAddrField<dyld_cache_image_clients_v2*>(patchInfo->patchClientsArrayAddr);
+ const auto* clientExports = getAddrField<dyld_cache_patchable_export_v2*>(patchInfo->patchClientExportsArrayAddr);
+ const auto* patchLocations = getAddrField<dyld_cache_patchable_location_v2*>(patchInfo->patchLocationArrayAddr);
+
+ // FIXME: This shouldn't be possible. The cache builder always adds 1 dyld_cache_image_patches_v2 per-image. But for now
+ // be conservative to match V1.
+ if (imageIndex > patchInfo->patchTableArrayCount)
+ return;
+
+ const dyld_cache_image_patches_v2& imagePatches = patchArray[imageIndex];
+ // FIXME: This shouldn't be possible. We should catch this in the builder instead
+ if ( (imagePatches.patchClientsStartIndex + imagePatches.patchClientsCount) > patchInfo->patchClientsArrayCount )
+ return;
+
+ for (uint64_t clientIndex = 0; clientIndex != imagePatches.patchClientsCount; ++clientIndex) {
+ const dyld_cache_image_clients_v2& client = clientArray[imagePatches.patchClientsStartIndex + clientIndex];
+
+ // FIXME: This shouldn't be possible. We should catch this in the builder instead
+ if ( (client.patchExportsStartIndex + client.patchExportsCount) > patchInfo->patchClientExportsArrayCount )
+ return;
+
+ for (uint64_t exportIndex = 0; exportIndex != client.patchExportsCount; ++exportIndex) {
+ const dyld_cache_patchable_export_v2& clientExport = clientExports[client.patchExportsStartIndex + exportIndex];
+
+ // The client export points to an image export from the image we are rooting
+ if ( clientExport.imageExportIndex > patchInfo->patchImageExportsArrayCount )
+ return;
+
+ const dyld_cache_image_export_v2& imageExport = imageExports[clientExport.imageExportIndex];
+
+ if ( imageExport.dylibOffsetOfImpl != dylibVMOffsetOfImpl )
+ continue;
+
+ if ( (clientExport.patchLocationsStartIndex + clientExport.patchLocationsCount) > patchInfo->patchLocationArrayCount )
+ return;
+
+ for (uint64_t locationIndex = 0; locationIndex != clientExport.patchLocationsCount; ++locationIndex) {
+ const dyld_cache_patchable_location_v2& patchLocation = patchLocations[clientExport.patchLocationsStartIndex + locationIndex];
+
+ dyld3::MachOLoaded::PointerMetaData pmd;
+ pmd.diversity = patchLocation.discriminator;
+ pmd.high8 = patchLocation.high7 << 1;
+ pmd.authenticated = patchLocation.authenticated;
+ pmd.key = patchLocation.key;
+ pmd.usesAddrDiversity = patchLocation.usesAddressDiversity;
+
+ handler(client.clientDylibIndex, patchLocation.dylibOffsetOfUse, pmd, patchLocation.getAddend());
+ }
+ }
+ }
+ return;
+ }
+
+ assert(false);
+}
bool DyldSharedCache::shouldPatchClientOfImage(uint32_t imageIndex, uint32_t userImageIndex) const {
if ( header.patchInfoAddr == 0 )
@@ -1272,14 +1299,37 @@
return false;
}
- // V2/V3 and newer structs
- PatchTable patchTable(this->patchTable(), header.patchInfoAddr);
- return patchTable.imageHasClient(imageIndex, userImageIndex);
+ // V2 and newer structs
+ if ( patchVersion == 2 ) {
+ const auto* patchInfo = getAddrField<dyld_cache_patch_info_v2*>(header.patchInfoAddr);
+ const auto* patchArray = getAddrField<dyld_cache_image_patches_v2*>(patchInfo->patchTableArrayAddr);
+ const auto* clientArray = getAddrField<dyld_cache_image_clients_v2*>(patchInfo->patchClientsArrayAddr);
+
+ // FIXME: This shouldn't be possible. The cache builder always adds 1 dyld_cache_image_patches_v2 per-image. But for now
+ // be conservative to match V1.
+ if (imageIndex > patchInfo->patchTableArrayCount)
+ return false;
+
+ const dyld_cache_image_patches_v2& imagePatches = patchArray[imageIndex];
+ // FIXME: This shouldn't be possible. We should catch this in the builder instead
+ if ( (imagePatches.patchClientsStartIndex + imagePatches.patchClientsCount) > patchInfo->patchClientsArrayCount )
+ return false;
+
+ for (uint64_t clientIndex = 0; clientIndex != imagePatches.patchClientsCount; ++clientIndex) {
+ const dyld_cache_image_clients_v2& client = clientArray[imagePatches.patchClientsStartIndex + clientIndex];
+
+ // We only want fixups in a specific image. Skip any others
+ if ( client.clientDylibIndex == userImageIndex )
+ return true;
+ }
+ return false;
+ }
+
+ assert(false);
}
void DyldSharedCache::forEachPatchableUseOfExportInImage(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl, uint32_t userImageIndex,
- void (^handler)(uint32_t userVMOffset, MachOLoaded::PointerMetaData pmd, uint64_t addend,
- bool isWeakImport)) const {
+ void (^handler)(uint32_t userVMOffset, MachOLoaded::PointerMetaData pmd, uint64_t addend)) const {
if ( header.patchInfoAddr == 0 )
return;
@@ -1387,30 +1437,88 @@
pmd.key = patchLocation.key;
pmd.usesAddrDiversity = patchLocation.usesAddressDiversity;
- handler(userVMOffset, pmd, patchLocation.getAddend(), false);
+ handler(userVMOffset, pmd, patchLocation.getAddend());
}
}
}
return;
}
- // V2/V3 and newer structs
- PatchTable patchTable(this->patchTable(), header.patchInfoAddr);
- patchTable.forEachPatchableUseOfExportInImage(imageIndex, dylibVMOffsetOfImpl,
- userImageIndex, handler);
+ // V2 and newer structs
+ if ( patchVersion == 2 ) {
+ const auto* patchInfo = getAddrField<dyld_cache_patch_info_v2*>(header.patchInfoAddr);
+ const auto* patchArray = getAddrField<dyld_cache_image_patches_v2*>(patchInfo->patchTableArrayAddr);
+ const auto* imageExports = getAddrField<dyld_cache_image_export_v2*>(patchInfo->patchImageExportsArrayAddr);
+ const auto* clientArray = getAddrField<dyld_cache_image_clients_v2*>(patchInfo->patchClientsArrayAddr);
+ const auto* clientExports = getAddrField<dyld_cache_patchable_export_v2*>(patchInfo->patchClientExportsArrayAddr);
+ const auto* patchLocations = getAddrField<dyld_cache_patchable_location_v2*>(patchInfo->patchLocationArrayAddr);
+
+ // FIXME: This shouldn't be possible. The cache builder always adds 1 dyld_cache_image_patches_v2 per-image. But for now
+ // be conservative to match V1.
+ if (imageIndex > patchInfo->patchTableArrayCount)
+ return;
+
+ const dyld_cache_image_patches_v2& imagePatches = patchArray[imageIndex];
+ // FIXME: This shouldn't be possible. We should catch this in the builder instead
+ if ( (imagePatches.patchClientsStartIndex + imagePatches.patchClientsCount) > patchInfo->patchClientsArrayCount )
+ return;
+
+ for (uint64_t clientIndex = 0; clientIndex != imagePatches.patchClientsCount; ++clientIndex) {
+ const dyld_cache_image_clients_v2& client = clientArray[imagePatches.patchClientsStartIndex + clientIndex];
+
+ // We only want fixups in a specific image. Skip any others
+ if ( client.clientDylibIndex != userImageIndex )
+ continue;
+
+ // FIXME: This shouldn't be possible. We should catch this in the builder instead
+ if ( (client.patchExportsStartIndex + client.patchExportsCount) > patchInfo->patchClientExportsArrayCount )
+ return;
+
+ for (uint64_t exportIndex = 0; exportIndex != client.patchExportsCount; ++exportIndex) {
+ const dyld_cache_patchable_export_v2& clientExport = clientExports[client.patchExportsStartIndex + exportIndex];
+
+ // The client export points to an image export from the image we are rooting
+ if ( clientExport.imageExportIndex > patchInfo->patchImageExportsArrayCount )
+ return;
+
+ const dyld_cache_image_export_v2& imageExport = imageExports[clientExport.imageExportIndex];
+
+ if ( imageExport.dylibOffsetOfImpl != dylibVMOffsetOfImpl )
+ continue;
+
+ if ( (clientExport.patchLocationsStartIndex + clientExport.patchLocationsCount) > patchInfo->patchLocationArrayCount )
+ return;
+
+ for (uint64_t locationIndex = 0; locationIndex != clientExport.patchLocationsCount; ++locationIndex) {
+ const dyld_cache_patchable_location_v2& patchLocation = patchLocations[clientExport.patchLocationsStartIndex + locationIndex];
+
+ dyld3::MachOLoaded::PointerMetaData pmd;
+ pmd.diversity = patchLocation.discriminator;
+ pmd.high8 = patchLocation.high7 << 1;
+ pmd.authenticated = patchLocation.authenticated;
+ pmd.key = patchLocation.key;
+ pmd.usesAddrDiversity = patchLocation.usesAddressDiversity;
+
+ handler(patchLocation.dylibOffsetOfUse, pmd, patchLocation.getAddend());
+ }
+ }
+
+ // We only wanted to process this image. We are now done
+ break;
+ }
+ return;
+ }
+
+ assert(false);
}
void DyldSharedCache::forEachPatchableUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
void (^handler)(uint64_t cacheVMOffset,
- MachOLoaded::PointerMetaData pmd, uint64_t addend,
- bool isWeakImport)) const {
+ MachOLoaded::PointerMetaData pmd, uint64_t addend)) const {
if ( header.patchInfoAddr == 0 )
return;
uint32_t patchVersion = patchInfoVersion();
-
- // Get GOT patches if we have them
- this->forEachPatchableGOTUseOfExport(imageIndex, dylibVMOffsetOfImpl, handler);
if ( patchVersion == 1 ) {
// Old cache. The patch table uses the V1 structs
@@ -1451,53 +1559,95 @@
pmd.key = patchLocation.key;
pmd.usesAddrDiversity = patchLocation.usesAddressDiversity;
- handler(patchLocation.cacheOffset, pmd, patchLocation.getAddend(), false);
+ handler(patchLocation.cacheOffset, pmd, patchLocation.getAddend());
}
}
return;
}
- // V2/V3 and newer structs
- auto getDylibAddress = ^(uint32_t dylibImageIndex) {
- auto* clientMF = (dyld3::MachOFile*)(this->getIndexedImageEntry(dylibImageIndex));
- if ( clientMF == nullptr )
- return 0ULL;
- return clientMF->preferredLoadAddress();
- };
- PatchTable patchTable(this->patchTable(), header.patchInfoAddr);
- patchTable.forEachPatchableCacheUseOfExport(imageIndex, dylibVMOffsetOfImpl,
- this->unslidLoadAddress(),
- getDylibAddress, handler);
-}
-
-void DyldSharedCache::forEachPatchableGOTUseOfExport(uint32_t imageIndex, uint32_t dylibVMOffsetOfImpl,
- void (^handler)(uint64_t cacheVMOffset,
- MachOFile::PointerMetaData pmd,
- uint64_t addend,
- bool isWeakImport)) const {
- if ( header.patchInfoAddr == 0 )
- return;
-
- uint32_t patchVersion = patchInfoVersion();
-
- if ( patchVersion == 1 ) {
- // Old cache. Only V3 has GOT patching
- return;
- }
-
- // V3 and newer structs
- PatchTable patchTable(this->patchTable(), header.patchInfoAddr);
- patchTable.forEachPatchableGOTUseOfExport(imageIndex, dylibVMOffsetOfImpl, handler);
+ // V2 and newer structs
+ if ( patchVersion == 2 ) {
+ const auto* patchInfo = getAddrField<dyld_cache_patch_info_v2*>(header.patchInfoAddr);
+ const auto* patchArray = getAddrField<dyld_cache_image_patches_v2*>(patchInfo->patchTableArrayAddr);
+ const auto* imageExports = getAddrField<dyld_cache_image_export_v2*>(patchInfo->patchImageExportsArrayAddr);
+ const auto* clientArray = getAddrField<dyld_cache_image_clients_v2*>(patchInfo->patchClientsArrayAddr);
+ const auto* clientExports = getAddrField<dyld_cache_patchable_export_v2*>(patchInfo->patchClientExportsArrayAddr);
+ const auto* patchLocations = getAddrField<dyld_cache_patchable_location_v2*>(patchInfo->patchLocationArrayAddr);
+
+ // FIXME: This shouldn't be possible. The cache builder always adds 1 dyld_cache_image_patches_v2 per-image. But for now
+ // be conservative to match V1.
+ if (imageIndex > patchInfo->patchTableArrayCount)
+ return;
+
+ const dyld_cache_image_patches_v2& imagePatches = patchArray[imageIndex];
+ // FIXME: This shouldn't be possible. We should catch this in the builder instead
+ if ( (imagePatches.patchClientsStartIndex + imagePatches.patchClientsCount) > patchInfo->patchClientsArrayCount )
+ return;
+
+ uint64_t cacheUnslidAddress = unslidLoadAddress();
+
+ for (uint64_t clientIndex = 0; clientIndex != imagePatches.patchClientsCount; ++clientIndex) {
+ const dyld_cache_image_clients_v2& client = clientArray[imagePatches.patchClientsStartIndex + clientIndex];
+
+ // FIXME: This shouldn't be possible. We should catch this in the builder instead
+ if ( (client.patchExportsStartIndex + client.patchExportsCount) > patchInfo->patchClientExportsArrayCount )
+ return;
+
+ // The callback wants a cache offset, so convert from "image + address" to a cache offset
+ uint64_t clientModTime;
+ uint64_t clientINode;
+ const dyld3::MachOAnalyzer* clientMA = (dyld3::MachOAnalyzer*)(this->getIndexedImageEntry(client.clientDylibIndex, clientModTime, clientINode));
+ if ( clientMA == nullptr )
+ return;
+
+ uint64_t clientUnslidAddress = clientMA->preferredLoadAddress();
+
+ for (uint64_t exportIndex = 0; exportIndex != client.patchExportsCount; ++exportIndex) {
+ const dyld_cache_patchable_export_v2& clientExport = clientExports[client.patchExportsStartIndex + exportIndex];
+
+ // The client export points to an image export from the image we are rooting
+ if ( clientExport.imageExportIndex > patchInfo->patchImageExportsArrayCount )
+ return;
+
+ const dyld_cache_image_export_v2& imageExport = imageExports[clientExport.imageExportIndex];
+
+ if ( imageExport.dylibOffsetOfImpl != dylibVMOffsetOfImpl )
+ continue;
+
+ if ( (clientExport.patchLocationsStartIndex + clientExport.patchLocationsCount) > patchInfo->patchLocationArrayCount )
+ return;
+
+ for (uint64_t locationIndex = 0; locationIndex != clientExport.patchLocationsCount; ++locationIndex) {
+ const dyld_cache_patchable_location_v2& patchLocation = patchLocations[clientExport.patchLocationsStartIndex + locationIndex];
+
+ dyld3::MachOLoaded::PointerMetaData pmd;
+ pmd.diversity = patchLocation.discriminator;
+ pmd.high8 = patchLocation.high7 << 1;
+ pmd.authenticated = patchLocation.authenticated;
+ pmd.key = patchLocation.key;
+ pmd.usesAddrDiversity = patchLocation.usesAddressDiversity;
+
+ uint64_t cacheOffset = (clientUnslidAddress + patchLocation.dylibOffsetOfUse) - cacheUnslidAddress;
+ handler(cacheOffset, pmd, patchLocation.getAddend());
+ }
+ }
+ }
+ return;
+ }
+
+ assert(false);
}
#if !(BUILDING_LIBDYLD || BUILDING_DYLD)
// MRM map file generator
-std::string DyldSharedCache::generateJSONMap(const char* disposition, uuid_t cache_uuid, bool verbose) const {
+std::string DyldSharedCache::generateJSONMap(const char* disposition) const {
dyld3::json::Node cacheNode;
cacheNode.map["version"].value = "1";
cacheNode.map["disposition"].value = disposition;
cacheNode.map["base-address"].value = dyld3::json::hex(unslidLoadAddress());
+ uuid_t cache_uuid;
+ getUUID(cache_uuid);
uuid_string_t cache_uuidStr;
uuid_unparse(cache_uuid, cache_uuidStr);
cacheNode.map["uuid"].value = cache_uuidStr;
@@ -1520,21 +1670,6 @@
segmentNode.map["name"].value = info.segName;
segmentNode.map["start-vmaddr"].value = dyld3::json::hex(info.vmAddr);
segmentNode.map["end-vmaddr"].value = dyld3::json::hex(info.vmAddr + info.vmSize);
-
- // Add sections in verbose mode
- if ( verbose ) {
- __block dyld3::json::Node sectionsNode;
- ma->forEachSection(^(const dyld3::MachOAnalyzer::SectionInfo& sectInfo, bool malformedSectionRange, bool& stopSection) {
- if ( sectInfo.segInfo.segIndex == info.segIndex ) {
- dyld3::json::Node sectionNode;
- sectionNode.map["name"].value = sectInfo.sectName;
- sectionNode.map["size"] = dyld3::json::Node(sectInfo.sectSize);
- sectionsNode.array.push_back(sectionNode);
- }
- });
- if ( !sectionsNode.array.empty() )
- segmentNode.map["sections"] = std::move(sectionsNode);
- }
segmentsNode.array.push_back(segmentNode);
});
imageNode.map["segments"] = segmentsNode;
@@ -1586,10 +1721,8 @@
// until we find one with slide info
forEachCache(^(const DyldSharedCache *cache, bool& stopCache) {
cache->forEachSlideInfo(^(uint64_t mappingStartAddress, uint64_t mappingSize, const uint8_t *mappingPagesStart, uint64_t slideInfoOffset, uint64_t slideInfoSize, const dyld_cache_slide_info *slideInfoHeader) {
- if ( slideInfoHeader->version == 1 ) {
- pointerFormat = VMAddrConverter::SharedCacheFormat::v1;
- pointerValueAdd = 0;
- } else if ( slideInfoHeader->version == 2 ) {
+ assert(slideInfoHeader->version >= 2);
+ if ( slideInfoHeader->version == 2 ) {
const dyld_cache_slide_info2* slideInfo = (dyld_cache_slide_info2*)(slideInfoHeader);
assert(slideInfo->delta_mask == 0x00FFFF0000000000);
pointerFormat = VMAddrConverter::SharedCacheFormat::v2_x86_64_tbi;
@@ -1623,19 +1756,13 @@
#endif
bool DyldSharedCache::inDyldCache(const DyldSharedCache* cache, const dyld3::MachOFile* mf) {
+ // FIXME: The cache PBLS has a null state.config.dyldCache.addr when built, so we can't do the
+ // range check. We might be able to remove the #if below if we can instead set the cache in the config.
+#if BUILDING_CACHE_BUILDER
+ return mf->inDyldCache();
+#else
return mf->inDyldCache() && (cache != nullptr) && ((uintptr_t)mf >= (uintptr_t)cache) && ((uintptr_t)mf < ((uintptr_t)cache + cache->mappedSize()));
-}
-
-bool DyldSharedCache::isSubCachePath(const char* leafName)
-{
- const char* firstDot = strchr(leafName, '.');
- // check for files with a suffix, to know wether or not they are sub-caches
- if ( firstDot != NULL ) {
- // skip files that are not of the format "<baseName>.development", as they are sub-caches
- if ( strcmp(firstDot, ".development") != 0 )
- return true;
- }
- return false;
+#endif
}
#if !(BUILDING_LIBDYLD || BUILDING_DYLD)
@@ -1644,8 +1771,6 @@
uint64_t baseCacheUnslidAddress,
uint8_t* buffer)
{
- // We don't need to map R-X as we aren't running the code here, so only allow mapping up to RW
- const uint32_t maxPermissions = VM_PROT_READ | VM_PROT_WRITE;
struct stat statbuf;
if ( ::stat(path, &statbuf) ) {
fprintf(stderr, "Error: stat failed for dyld shared cache at %s\n", path);
@@ -1664,11 +1789,6 @@
return nullptr;
}
const dyld_cache_header* header = (dyld_cache_header*)firstPage;
- if ( strncmp(header->magic, "dyld_v1", 7) != 0 ) {
- fprintf(stderr, "Error: Expected cache file magic to be 'dyld_v1...' in %s\n", path);
- return nullptr;
- }
-
if ( header->mappingCount == 0 ) {
fprintf(stderr, "Error: No mapping in shared cache file at %s\n", path);
return nullptr;
@@ -1699,7 +1819,7 @@
for (uint32_t i=0; i < header->mappingCount; ++i) {
uint64_t mappingAddressOffset = mappings[i].address - mappings[0].address;
void* mapped_cache = ::mmap((void*)(buffer + mappingAddressOffset + subCacheBufferOffset), (size_t)mappings[i].size,
- mappings[i].maxProt & maxPermissions, MAP_FIXED | MAP_PRIVATE, cache_fd, mappings[i].fileOffset);
+ mappings[i].maxProt, MAP_FIXED | MAP_PRIVATE, cache_fd, mappings[i].fileOffset);
if (mapped_cache == MAP_FAILED) {
fprintf(stderr, "Error: mmap() for shared cache at %s failed, errno=%d\n", path, errno);
return nullptr;
@@ -1719,33 +1839,20 @@
std::vector<const DyldSharedCache*> caches;
caches.push_back(cache);
- std::string basePath = std::string(path);
- if ( cache->header.cacheType == kDyldSharedCacheTypeUniversal )
- {
- std::size_t pos = basePath.find(DYLD_SHARED_CACHE_DEVELOPMENT_EXT);
- if (pos != std::string::npos)
- basePath = basePath.substr(0, basePath.size() - 12);
- }
// Load all subcaches, if we have them
if ( cache->header.mappingOffset >= __offsetof(dyld_cache_header, subCacheArrayCount) ) {
if ( cache->header.subCacheArrayCount != 0 ) {
const dyld_subcache_entry* subCacheEntries = (dyld_subcache_entry*)((uint8_t*)cache + cache->header.subCacheArrayOffset);
- bool hasCacheSuffix = cache->header.mappingOffset > __offsetof(dyld_cache_header, cacheSubType);
for (uint32_t i = 0; i != cache->header.subCacheArrayCount; ++i) {
- std::string subCachePath = std::string(path) + "." + dyld3::json::unpaddedDecimal(i + 1);
- if ( hasCacheSuffix ) {
- subCachePath = basePath + subCacheEntries[i].fileSuffix;
- }
+ std::string subCachePath = std::string(path) + "." + dyld3::json::decimal(i + 1);
const DyldSharedCache* subCache = DyldSharedCache::mapCacheFile(subCachePath.c_str(), cache->unslidLoadAddress(), (uint8_t*)cache);
if ( subCache == nullptr )
return {};
- uint8_t uuid[16];
- cache->getSubCacheUuid(i, uuid);
- if ( memcmp(subCache->header.uuid, uuid, 16) != 0 ) {
+ if ( memcmp(subCache->header.uuid, subCacheEntries[i].uuid, 16) != 0 ) {
uuid_string_t expectedUUIDString;
- uuid_unparse_upper(uuid, expectedUUIDString);
+ uuid_unparse_upper(subCacheEntries[i].uuid, expectedUUIDString);
uuid_string_t foundUUIDString;
uuid_unparse_upper(subCache->header.uuid, foundUUIDString);
fprintf(stderr, "Error: SubCache[%i] UUID mismatch. Expected %s, got %s\n", i, expectedUUIDString, foundUUIDString);
@@ -1859,21 +1966,7 @@
return (uint8_t*)(legacyCacheDataRegionMapping()->address) + slide;
}
-const ObjCOptimizationHeader* DyldSharedCache::objcOpts() const
-{
- if ( header.mappingOffset <= __offsetof(dyld_cache_header, objcOptsSize) )
- return nullptr;
-
- return (const ObjCOptimizationHeader*)((char*)this + header.objcOptsOffset);
-}
-
-#if BUILDING_CACHE_BUILDER
-const objc_opt::objc_opt_t* DyldSharedCache::oldObjcOpt() const
-{
- return nullptr;
-}
-#else
-const objc_opt::objc_opt_t* DyldSharedCache::oldObjcOpt() const
+const objc_opt::objc_opt_t* DyldSharedCache::objcOpt() const
{
// Find the objc image
__block const dyld3::MachOAnalyzer* objcMA = nullptr;
@@ -1882,6 +1975,15 @@
uint64_t mTime;
uint64_t inode;
objcMA = (dyld3::MachOAnalyzer*)(this->getIndexedImageEntry(imageIndex, mTime, inode));
+ } else {
+#if BUILDING_CACHE_BUILDER
+ // The cache builder might call this before prior to the trie being written.
+ // In this case, we can still use the image list which is always available
+ forEachImage(^(const mach_header *mh, const char *installName) {
+ if ( !strcmp(installName, "/usr/lib/libobjc.A.dylib") )
+ objcMA = (const dyld3::MachOAnalyzer*)mh;
+ });
+#endif
}
if ( objcMA == nullptr )
@@ -1910,7 +2012,6 @@
return nullptr;
}
-#endif
const void* DyldSharedCache::objcOptPtrs() const
{
@@ -1949,109 +2050,31 @@
return objcPointersContent;
}
-bool DyldSharedCache::hasOptimizedObjC() const
-{
- return (this->objcOpts() != nullptr) || (this->oldObjcOpt() != nullptr);
-}
-
-uint32_t DyldSharedCache::objcOptVersion() const
-{
- if ( const ObjCOptimizationHeader* opts = this->objcOpts() )
- return opts->version;
- if ( const objc_opt::objc_opt_t* opts = this->oldObjcOpt() )
- return opts->version;
- return 0;
-}
-
-uint32_t DyldSharedCache::objcOptFlags() const
-{
- if ( const ObjCOptimizationHeader* opts = this->objcOpts() )
- return 0;
- if ( const objc_opt::objc_opt_t* opts = this->oldObjcOpt() )
- return opts->flags;
- return 0;
-}
-
-const objc::HeaderInfoRO* DyldSharedCache::objcHeaderInfoRO() const
-{
- if ( const ObjCOptimizationHeader* opts = this->objcOpts() ) {
- if ( opts->headerInfoROCacheOffset != 0 )
- return (const objc::HeaderInfoRO*)((char*)this + opts->headerInfoROCacheOffset);
- return nullptr;
- }
- if ( const objc_opt::objc_opt_t* opts = this->oldObjcOpt() )
- return (const objc::HeaderInfoRO*)opts->headeropt_ro();
- return nullptr;
-}
-
-const objc::HeaderInfoRW* DyldSharedCache::objcHeaderInfoRW() const
-{
- if ( const ObjCOptimizationHeader* opts = this->objcOpts() ) {
- if ( opts->headerInfoRWCacheOffset != 0 )
- return (const objc::HeaderInfoRW*)((char*)this + opts->headerInfoRWCacheOffset);
- return nullptr;
- }
- if ( const objc_opt::objc_opt_t* opts = this->oldObjcOpt() )
- return (const objc::HeaderInfoRW*)opts->headeropt_rw();
- return nullptr;
-}
-
-const objc::SelectorHashTable* DyldSharedCache::objcSelectorHashTable() const
-{
- if ( const ObjCOptimizationHeader* opts = this->objcOpts() ) {
- if ( opts->selectorHashTableCacheOffset != 0 )
- return (const objc::SelectorHashTable*)((char*)this + opts->selectorHashTableCacheOffset);
- return nullptr;
- }
- if ( const objc_opt::objc_opt_t* opts = this->oldObjcOpt() )
- return opts->selectorOpt();
- return nullptr;
-}
-
-const objc::ClassHashTable* DyldSharedCache::objcClassHashTable() const
-{
- if ( const ObjCOptimizationHeader* opts = this->objcOpts() ) {
- if ( opts->classHashTableCacheOffset != 0 )
- return (const objc::ClassHashTable*)((char*)this + opts->classHashTableCacheOffset);
- return nullptr;
- }
- if ( const objc_opt::objc_opt_t* opts = this->oldObjcOpt() )
- return opts->classOpt();
- return nullptr;
-}
-
-const objc::ProtocolHashTable* DyldSharedCache::objcProtocolHashTable() const
-{
- if ( const ObjCOptimizationHeader* opts = this->objcOpts() ) {
- if ( opts->protocolHashTableCacheOffset != 0 )
- return (const objc::ProtocolHashTable*)((char*)this + opts->protocolHashTableCacheOffset);
- return nullptr;
- }
- if ( const objc_opt::objc_opt_t* opts = this->oldObjcOpt() )
- return opts->protocolOpt();
- return nullptr;
-}
-
-const void* DyldSharedCache::objcRelativeMethodListsBaseAddress() const
-{
- if ( const ObjCOptimizationHeader* opts = this->objcOpts() ) {
- if ( opts->relativeMethodSelectorBaseAddressOffset != 0 )
- return (const void*)((char*)this + opts->relativeMethodSelectorBaseAddressOffset);
- return nullptr;
- }
- if ( const objc_opt::objc_opt_t* opts = this->oldObjcOpt() )
- return opts->relativeMethodListsBaseAddress();
- return nullptr;
-}
-
#if !(BUILDING_LIBDYLD || BUILDING_DYLD)
uint64_t DyldSharedCache::sharedCacheRelativeSelectorBaseVMAddress() const {
- const void* value = this->objcRelativeMethodListsBaseAddress();
- if ( !value )
+ if ( header.mappingOffset <= __offsetof(dyld_cache_header, symbolFileUUID) )
return 0;
- uint64_t vmOffset = (uint64_t)value - (uint64_t)this;
- return this->unslidLoadAddress() + vmOffset;
+ // In newer shared caches, relative method list selectors are offsets from the magic selector in libobjc
+ __block uint64_t sharedCacheRelativeSelectorBaseVMAddress = 0;
+ constexpr std::string_view magicSelector = "\xf0\x9f\xa4\xaf";
+ dyld3::MachOAnalyzer::VMAddrConverter vmAddrConverter = makeVMAddrConverter(false);
+ uint64_t sharedCacheSlide = (uint64_t)this - unslidLoadAddress();
+ forEachImage(^(const mach_header *mh, const char *installName) {
+ if ( !strcmp(installName, "/usr/lib/libobjc.A.dylib") ) {
+ const dyld3::MachOAnalyzer* ma = (const dyld3::MachOAnalyzer*)mh;
+ Diagnostics diag;
+ ma->forEachObjCSelectorReference(diag, vmAddrConverter,
+ ^(uint64_t selRefVMAddr, uint64_t selRefTargetVMAddr, bool &stop) {
+ const char* selValue = (const char*)(selRefTargetVMAddr + sharedCacheSlide);
+ if ( selValue == magicSelector ) {
+ sharedCacheRelativeSelectorBaseVMAddress = selRefTargetVMAddr;
+ stop = true;
+ }
+ });
+ }
+ });
+ return sharedCacheRelativeSelectorBaseVMAddress;
}
#endif
@@ -2210,5 +2233,3 @@
});
}
#endif
-
-#endif // !TARGET_OS_EXCLAVEKIT