diff options
Diffstat (limited to 'view/sharedcache/core/SharedCache.cpp')
| -rw-r--r-- | view/sharedcache/core/SharedCache.cpp | 448 |
1 files changed, 251 insertions, 197 deletions
diff --git a/view/sharedcache/core/SharedCache.cpp b/view/sharedcache/core/SharedCache.cpp index c1ff902e..f76ee1ad 100644 --- a/view/sharedcache/core/SharedCache.cpp +++ b/view/sharedcache/core/SharedCache.cpp @@ -53,30 +53,33 @@ int count_trailing_zeros(uint64_t value) { } #endif -struct ViewStateCacheStore { - SharedCache::SharedCacheFormat m_cacheFormat; +struct SharedCache::State +{ + std::unordered_map<uint64_t, std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>>> + exportInfos; + std::unordered_map<uint64_t, std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>>> + symbolInfos; - DSCViewState m_viewState; + std::unordered_map<std::string, uint64_t> imageStarts; + std::unordered_map<uint64_t, SharedCacheMachOHeader> headers; - std::unordered_map<std::string, uint64_t> m_imageStarts; - std::unordered_map<uint64_t, SharedCacheMachOHeader> m_headers; + std::vector<CacheImage> images; - std::vector<CacheImage> m_images; - std::vector<MemoryRegion> m_regionsMappedIntoMemory; + std::vector<MemoryRegion> regionsMappedIntoMemory; - std::vector<BackingCache> m_backingCaches; - std::vector<MemoryRegion> m_stubIslandRegions; // TODO honestly both of these should be refactored into nonImageRegions. :p - std::vector<MemoryRegion> m_dyldDataRegions; - std::vector<MemoryRegion> m_nonImageRegions; + std::vector<BackingCache> backingCaches; - std::string m_baseFilePath; + std::vector<MemoryRegion> stubIslandRegions; // TODO honestly both of these should be refactored into nonImageRegions. :p + std::vector<MemoryRegion> dyldDataRegions; + std::vector<MemoryRegion> nonImageRegions; - std::unordered_map<uint64_t, std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>>> m_exportInfos; - std::unordered_map<uint64_t, std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>>> m_symbolInfos; + std::string baseFilePath; + SharedCacheFormat cacheFormat; + DSCViewState viewState = DSCViewStateUnloaded; }; static std::recursive_mutex viewStateMutex; -static std::unordered_map<uint64_t, ViewStateCacheStore> viewStateCache; +static std::unordered_map<uint64_t, std::shared_ptr<struct SharedCache::State>> viewStateCache; std::mutex progressMutex; std::unordered_map<uint64_t, BNDSCViewLoadProgress> progressMap; @@ -221,7 +224,9 @@ void SharedCache::PerformInitialLoad() progressMap[m_dscView->GetFile()->GetSessionId()] = LoadProgressLoadingCaches; progressMutex.unlock(); - m_baseFilePath = path; + WillMutateState(); + + MutableState().baseFilePath = path; DataBuffer sig = baseFile->ReadBuffer(0, 4); if (sig.GetLength() != 4) @@ -230,14 +235,14 @@ void SharedCache::PerformInitialLoad() if (strncmp(magic, "dyld", 4) != 0) abort(); - m_cacheFormat = RegularCacheFormat; + MutableState().cacheFormat = RegularCacheFormat; dyld_cache_header primaryCacheHeader {}; size_t header_size = baseFile->ReadUInt32(16); baseFile->Read(&primaryCacheHeader, 0, std::min(header_size, sizeof(dyld_cache_header))); if (primaryCacheHeader.imagesCountOld != 0) - m_cacheFormat = RegularCacheFormat; + MutableState().cacheFormat = RegularCacheFormat; size_t subCacheOff = offsetof(struct dyld_cache_header, subCacheArrayOffset); size_t headerEnd = primaryCacheHeader.mappingOffset; @@ -246,15 +251,15 @@ void SharedCache::PerformInitialLoad() if (primaryCacheHeader.cacheType != 2) { if (std::filesystem::exists(ResolveFilePath(m_dscView, baseFile->Path() + ".01"))) - m_cacheFormat = LargeCacheFormat; + MutableState().cacheFormat = LargeCacheFormat; else - m_cacheFormat = SplitCacheFormat; + MutableState().cacheFormat = SplitCacheFormat; } else - m_cacheFormat = iOS16CacheFormat; + MutableState().cacheFormat = iOS16CacheFormat; } - switch (m_cacheFormat) + switch (State().cacheFormat) { case RegularCacheFormat: { @@ -272,7 +277,7 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.second.second = mapping.size; cache.mappings.push_back(mapRawToAddrAndSize); } - m_backingCaches.push_back(cache); + MutableState().backingCaches.push_back(std::move(cache)); dyld_cache_image_info img {}; @@ -280,7 +285,7 @@ void SharedCache::PerformInitialLoad() { baseFile->Read(&img, primaryCacheHeader.imagesOffsetOld + (i * sizeof(img)), sizeof(img)); auto iname = baseFile->ReadNullTermString(img.pathFileOffset); - m_imageStarts[iname] = img.address; + MutableState().imageStarts[iname] = img.address; } m_logger->LogInfo("Found %d images in the shared cache", primaryCacheHeader.imagesCountOld); @@ -312,7 +317,7 @@ void SharedCache::PerformInitialLoad() std::string segNameStr = std::string(segName); stubIslandRegion.prettyName = "dyld_shared_cache_branch_islands_" + std::to_string(i) + "::" + segNameStr; stubIslandRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_stubIslandRegions.push_back(stubIslandRegion); + MutableState().stubIslandRegions.push_back(std::move(stubIslandRegion)); } } } @@ -338,9 +343,9 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = mapping.fileOffset; mapRawToAddrAndSize.second.first = mapping.address; mapRawToAddrAndSize.second.second = mapping.size; - cache.mappings.push_back(mapRawToAddrAndSize); + cache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(cache); + MutableState().backingCaches.push_back(std::move(cache)); dyld_cache_image_info img {}; @@ -348,7 +353,7 @@ void SharedCache::PerformInitialLoad() { baseFile->Read(&img, primaryCacheHeader.imagesOffset + (i * sizeof(img)), sizeof(img)); auto iname = baseFile->ReadNullTermString(img.pathFileOffset); - m_imageStarts[iname] = img.address; + MutableState().imageStarts[iname] = img.address; } if (primaryCacheHeader.branchPoolsCount) @@ -356,7 +361,8 @@ void SharedCache::PerformInitialLoad() std::vector<uint64_t> pool {}; for (size_t i = 0; i < primaryCacheHeader.branchPoolsCount; i++) { - m_imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); + MutableState().imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = + baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); } } std::string mainFileName = base_name(path); @@ -413,7 +419,7 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); } if (subCacheHeader.mappingCount == 1 && subCacheHeader.imagesCountOld == 0 && subCacheHeader.imagesCount == 0 @@ -427,10 +433,10 @@ void SharedCache::PerformInitialLoad() stubIslandRegion.size = size; stubIslandRegion.prettyName = subCacheFilename + "::_stubs"; stubIslandRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_stubIslandRegions.push_back(stubIslandRegion); + MutableState().stubIslandRegions.push_back(std::move(stubIslandRegion)); } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); } break; } @@ -449,9 +455,9 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = mapping.fileOffset; mapRawToAddrAndSize.second.first = mapping.address; mapRawToAddrAndSize.second.second = mapping.size; - cache.mappings.push_back(mapRawToAddrAndSize); + cache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(cache); + MutableState().backingCaches.push_back(std::move(cache)); dyld_cache_image_info img {}; @@ -459,7 +465,7 @@ void SharedCache::PerformInitialLoad() { baseFile->Read(&img, primaryCacheHeader.imagesOffset + (i * sizeof(img)), sizeof(img)); auto iname = baseFile->ReadNullTermString(img.pathFileOffset); - m_imageStarts[iname] = img.address; + MutableState().imageStarts[iname] = img.address; } if (primaryCacheHeader.branchPoolsCount) @@ -467,7 +473,8 @@ void SharedCache::PerformInitialLoad() std::vector<uint64_t> pool {}; for (size_t i = 0; i < primaryCacheHeader.branchPoolsCount; i++) { - m_imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); + MutableState().imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = + baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); } } @@ -508,10 +515,10 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); if (subCacheHeader.mappingCount == 1 && subCacheHeader.imagesCountOld == 0 && subCacheHeader.imagesCount == 0 && subCacheHeader.imagesTextOffset == 0) @@ -524,7 +531,7 @@ void SharedCache::PerformInitialLoad() stubIslandRegion.size = size; stubIslandRegion.prettyName = subCacheFilename + "::_stubs"; stubIslandRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_stubIslandRegions.push_back(stubIslandRegion); + MutableState().stubIslandRegions.push_back(std::move(stubIslandRegion)); } } @@ -554,10 +561,10 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); break; } case iOS16CacheFormat: @@ -575,10 +582,10 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = mapping.fileOffset; mapRawToAddrAndSize.second.first = mapping.address; mapRawToAddrAndSize.second.second = mapping.size; - cache.mappings.push_back(mapRawToAddrAndSize); + cache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(cache); + MutableState().backingCaches.push_back(std::move(cache)); dyld_cache_image_info img {}; @@ -586,7 +593,7 @@ void SharedCache::PerformInitialLoad() { baseFile->Read(&img, primaryCacheHeader.imagesOffset + (i * sizeof(img)), sizeof(img)); auto iname = baseFile->ReadNullTermString(img.pathFileOffset); - m_imageStarts[iname] = img.address; + MutableState().imageStarts[iname] = img.address; } if (primaryCacheHeader.branchPoolsCount) @@ -594,7 +601,8 @@ void SharedCache::PerformInitialLoad() std::vector<uint64_t> pool {}; for (size_t i = 0; i < primaryCacheHeader.branchPoolsCount; i++) { - m_imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); + MutableState().imageStarts["dyld_shared_cache_branch_islands_" + std::to_string(i)] = + baseFile->ReadULong(primaryCacheHeader.branchPoolsOffset + (i * m_dscView->GetAddressSize())); } } @@ -657,7 +665,7 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); if (subCachePath.find(".dylddata") != std::string::npos) { @@ -669,11 +677,11 @@ void SharedCache::PerformInitialLoad() dyldDataRegion.size = size; dyldDataRegion.prettyName = subCacheFilename + "::_data" + std::to_string(j); dyldDataRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable); - m_dyldDataRegions.push_back(dyldDataRegion); + MutableState().dyldDataRegions.push_back(std::move(dyldDataRegion)); } } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); if (subCacheHeader.mappingCount == 1 && subCacheHeader.imagesCountOld == 0 && subCacheHeader.imagesCount == 0 && subCacheHeader.imagesTextOffset == 0) @@ -686,7 +694,7 @@ void SharedCache::PerformInitialLoad() stubIslandRegion.size = size; stubIslandRegion.prettyName = subCacheFilename + "::_stubs"; stubIslandRegion.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_stubIslandRegions.push_back(stubIslandRegion); + MutableState().stubIslandRegions.push_back(std::move(stubIslandRegion)); } } @@ -718,10 +726,10 @@ void SharedCache::PerformInitialLoad() mapRawToAddrAndSize.first = subCacheMapping.fileOffset; mapRawToAddrAndSize.second.first = subCacheMapping.address; mapRawToAddrAndSize.second.second = subCacheMapping.size; - subCache.mappings.push_back(mapRawToAddrAndSize); + subCache.mappings.push_back(std::move(mapRawToAddrAndSize)); } - m_backingCaches.push_back(subCache); + MutableState().backingCaches.push_back(std::move(subCache)); } catch (...) {} @@ -741,7 +749,7 @@ void SharedCache::PerformInitialLoad() m_logger->LogError("Failed to map VM pages for Shared Cache on initial load, this is fatal."); return; } - for (const auto &start : m_imageStarts) + for (const auto& start : State().imageStarts) { try { auto imageHeader = SharedCache::LoadHeaderForAddress(vm, start.second, start.first); @@ -752,7 +760,7 @@ void SharedCache::PerformInitialLoad() auto mapping = vm->MappingAtAddress(imageHeader->linkeditSegment.vmaddr); imageHeader->exportTriePath = mapping.first.filePath; } - m_headers[start.second] = imageHeader.value(); + MutableState().headers[start.second] = imageHeader.value(); CacheImage image; image.installName = start.first; image.headerLocation = start.second; @@ -781,14 +789,14 @@ void SharedCache::PerformInitialLoad() // if we're positive we have an entry point for some reason, force the segment // executable. this helps with kernel images. - for (auto &entryPoint: imageHeader->m_entryPoints) + for (auto &entryPoint : imageHeader->m_entryPoints) if (segment.vmaddr <= entryPoint && (entryPoint < (segment.vmaddr + segment.filesize))) flags |= SegmentExecutable; sectionRegion.flags = (BNSegmentFlag)flags; image.regions.push_back(sectionRegion); } - m_images.push_back(image); + MutableState().images.push_back(image); } else { @@ -801,9 +809,9 @@ void SharedCache::PerformInitialLoad() } } - m_logger->LogInfo("Loaded %d Mach-O headers", m_headers.size()); + m_logger->LogInfo("Loaded %d Mach-O headers", State().headers.size()); - for (const auto& cache : m_backingCaches) + for (const auto& cache : State().backingCaches) { size_t i = 0; for (const auto& mapping : cache.mappings) @@ -814,15 +822,15 @@ void SharedCache::PerformInitialLoad() region.prettyName = base_name(cache.path) + "::" + std::to_string(i); // FIXME flags!!! BackingCache.mapping needs refactored to store this information! region.flags = (BNSegmentFlag)(BNSegmentFlag::SegmentReadable | BNSegmentFlag::SegmentExecutable); - m_nonImageRegions.push_back(region); + MutableState().nonImageRegions.push_back(std::move(region)); i++; } } // Iterate through each Mach-O header - if (!m_dyldDataRegions.empty()) + if (!State().dyldDataRegions.empty()) { - for (const auto& [headerKey, header] : m_headers) + for (const auto& [headerKey, header] : State().headers) { // Iterate through each segment of the header for (const auto& segment : header.segments) @@ -831,7 +839,7 @@ void SharedCache::PerformInitialLoad() uint64_t segmentEnd = segmentStart + segment.vmsize; // Iterate through each region in m_dyldDataRegions - for (auto it = m_dyldDataRegions.begin(); it != m_dyldDataRegions.end();) + for (auto it = State().dyldDataRegions.begin(); it != State().dyldDataRegions.end();) { uint64_t regionStart = it->start; uint64_t regionSize = it->size; @@ -862,12 +870,12 @@ void SharedCache::PerformInitialLoad() } // Erase the original region - it = m_dyldDataRegions.erase(it); + it = MutableState().dyldDataRegions.erase(it); // Insert the new regions (if any) for (const auto& newRegion : newRegions) { - it = m_dyldDataRegions.insert(it, newRegion); + it = MutableState().dyldDataRegions.insert(it, newRegion); ++it; // Move iterator to the next position } } @@ -881,9 +889,9 @@ void SharedCache::PerformInitialLoad() } // Iterate through each Mach-O header - if (!m_nonImageRegions.empty()) + if (!State().nonImageRegions.empty()) { - for (const auto& [headerKey, header] : m_headers) + for (const auto& [headerKey, header] : State().headers) { // Iterate through each segment of the header for (const auto& segment : header.segments) @@ -892,7 +900,7 @@ void SharedCache::PerformInitialLoad() uint64_t segmentEnd = segmentStart + segment.vmsize; // Iterate through each region in m_dyldDataRegions - for (auto it = m_nonImageRegions.begin(); it != m_nonImageRegions.end();) + for (auto it = State().nonImageRegions.begin(); it != State().nonImageRegions.end();) { uint64_t regionStart = it->start; uint64_t regionSize = it->size; @@ -923,12 +931,12 @@ void SharedCache::PerformInitialLoad() } // Erase the original region - it = m_nonImageRegions.erase(it); + it = MutableState().nonImageRegions.erase(it); // Insert the new regions (if any) for (const auto& newRegion : newRegions) { - it = m_nonImageRegions.insert(it, newRegion); + it = MutableState().nonImageRegions.insert(it, newRegion); ++it; // Move iterator to the next position } } @@ -955,7 +963,7 @@ std::shared_ptr<VM> SharedCache::GetVMMap(bool mapPages) if (mapPages) { - for (const auto& cache : m_backingCaches) + for (const auto& cache : State().backingCaches) { for (const auto& mapping : cache.mappings) { @@ -976,22 +984,10 @@ void SharedCache::DeserializeFromRawView() if (m_dscView->QueryMetadata(SharedCacheMetadataTag)) { std::unique_lock<std::recursive_mutex> viewStateCacheLock(viewStateMutex); - if (viewStateCache.find(m_dscView->GetFile()->GetSessionId()) != viewStateCache.end()) + if (auto it = viewStateCache.find(m_dscView->GetFile()->GetSessionId()); it != viewStateCache.end()) { - auto c = viewStateCache[m_dscView->GetFile()->GetSessionId()]; - m_imageStarts = c.m_imageStarts; - m_cacheFormat = c.m_cacheFormat; - m_backingCaches = c.m_backingCaches; - m_viewState = c.m_viewState; - m_headers = c.m_headers; - m_images = c.m_images; - m_regionsMappedIntoMemory = c.m_regionsMappedIntoMemory; - m_stubIslandRegions = c.m_stubIslandRegions; - m_dyldDataRegions = c.m_dyldDataRegions; - m_nonImageRegions = c.m_nonImageRegions; - m_baseFilePath = c.m_baseFilePath; - m_exportInfos = c.m_exportInfos; - m_symbolInfos = c.m_symbolInfos; + m_state = it->second; + m_stateIsShared = true; m_metadataValid = true; } else @@ -1001,14 +997,16 @@ void SharedCache::DeserializeFromRawView() if (!m_metadataValid) { m_logger->LogError("Failed to deserialize Shared Cache metadata"); - m_viewState = DSCViewStateUnloaded; + WillMutateState(); + MutableState().viewState = DSCViewStateUnloaded; } } else { m_metadataValid = true; - m_viewState = DSCViewStateUnloaded; - m_images.clear(); // fixme ?? + WillMutateState(); + MutableState().viewState = DSCViewStateUnloaded; + MutableState().images.clear(); // fixme ?? } } @@ -1025,12 +1023,14 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAcces { if (file->SlideInfoWasApplied()) return; + + WillMutateState(); std::vector<std::pair<uint64_t, uint64_t>> rewrites; dyld_cache_header baseHeader; file->Read(&baseHeader, 0, sizeof(dyld_cache_header)); uint64_t base = UINT64_MAX; - for (const auto& backingCache : m_backingCaches) + for (const auto& backingCache : State().backingCaches) { for (const auto& mapping : backingCache.mappings) { @@ -1361,42 +1361,39 @@ SharedCache::SharedCache(BinaryNinja::Ref<BinaryNinja::BinaryView> dscView) : m_ DeserializeFromRawView(); if (!m_metadataValid) return; - if (m_viewState == DSCViewStateUnloaded) + if (State().viewState == DSCViewStateUnloaded) { - if (m_viewState == DSCViewStateUnloaded) + std::unique_lock<std::mutex> lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); + try { + PerformInitialLoad(); + } + catch (...) { - std::unique_lock<std::mutex> lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); - try { - PerformInitialLoad(); - } - catch (...) - { - m_logger->LogError("Failed to perform initial load of Shared Cache"); - } + m_logger->LogError("Failed to perform initial load of Shared Cache"); + } - auto settings = m_dscView->GetLoadSettings(VIEW_NAME); - bool autoLoadLibsystem = true; - if (settings && settings->Contains("loader.dsc.autoLoadLibSystem")) - { - autoLoadLibsystem = settings->Get<bool>("loader.dsc.autoLoadLibSystem", m_dscView); - } - if (autoLoadLibsystem) + auto settings = m_dscView->GetLoadSettings(VIEW_NAME); + bool autoLoadLibsystem = true; + if (settings && settings->Contains("loader.dsc.autoLoadLibSystem")) + { + autoLoadLibsystem = settings->Get<bool>("loader.dsc.autoLoadLibSystem", m_dscView); + } + if (autoLoadLibsystem) + { + for (const auto& [_, header] : State().headers) { - for (const auto& [_, header] : m_headers) + if (header.installName.find("libsystem_c.dylib") != std::string::npos) { - if (header.installName.find("libsystem_c.dylib") != std::string::npos) - { - lock.unlock(); - m_logger->LogInfo("Loading core libsystem_c.dylib library"); - LoadImageWithInstallName(header.installName); - lock.lock(); - break; - } + lock.unlock(); + m_logger->LogInfo("Loading core libsystem_c.dylib library"); + LoadImageWithInstallName(header.installName); + lock.lock(); + break; } } - m_viewState = DSCViewStateLoaded; - SaveToDSCView(); } + MutableState().viewState = DSCViewStateLoaded; + SaveToDSCView(); } else { @@ -1426,7 +1423,7 @@ SharedCache* SharedCache::GetFromDSCView(BinaryNinja::Ref<BinaryNinja::BinaryVie std::optional<uint64_t> SharedCache::GetImageStart(std::string installName) { - for (const auto& [name, start] : m_imageStarts) + for (const auto& [name, start] : State().imageStarts) { if (name == installName) { @@ -1441,7 +1438,7 @@ std::optional<SharedCacheMachOHeader> SharedCache::HeaderForAddress(uint64_t add // We _could_ mark each page with the image start? :grimacing emoji: // But that'd require mapping pages :grimacing emoji: :grimacing emoji: // There's not really any other hacks that could make this faster, that I can think of... - for (const auto& [start, header] : m_headers) + for (const auto& [start, header] : State().headers) { for (const auto& segment : header.segments) { @@ -1456,21 +1453,21 @@ std::optional<SharedCacheMachOHeader> SharedCache::HeaderForAddress(uint64_t add std::string SharedCache::NameForAddress(uint64_t address) { - for (const auto& stubIsland : m_stubIslandRegions) + for (const auto& stubIsland : State().stubIslandRegions) { if (stubIsland.start <= address && stubIsland.start + stubIsland.size > address) { return stubIsland.prettyName; } } - for (const auto& dyldData : m_dyldDataRegions) + for (const auto& dyldData : State().dyldDataRegions) { if (dyldData.start <= address && dyldData.start + dyldData.size > address) { return dyldData.prettyName; } } - for (const auto& nonImageRegion : m_nonImageRegions) + for (const auto& nonImageRegion : State().nonImageRegions) { if (nonImageRegion.start <= address && nonImageRegion.start + nonImageRegion.size > address) { @@ -1504,7 +1501,7 @@ std::string SharedCache::ImageNameForAddress(uint64_t address) bool SharedCache::LoadImageContainingAddress(uint64_t address) { - for (const auto& [start, header] : m_headers) + for (const auto& [start, header] : State().headers) { for (const auto& segment : header.segments) { @@ -1522,6 +1519,8 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) { std::unique_lock<std::mutex> lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); DeserializeFromRawView(); + WillMutateState(); + auto vm = GetVMMap(); if (!vm) { @@ -1533,13 +1532,13 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) CacheImage* targetImage = nullptr; MemoryRegion* targetSegment = nullptr; - for (auto& image : m_images) + for (auto& image : MutableState().images) { for (auto& region : image.regions) { if (region.start <= address && region.start + region.size > address) { - targetHeader = m_headers[image.headerLocation]; + targetHeader = MutableState().headers[image.headerLocation]; targetImage = ℑ targetSegment = ®ion; break; @@ -1550,7 +1549,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) } if (!targetSegment) { - for (auto& stubIsland : m_stubIslandRegions) + for (auto& stubIsland : MutableState().stubIslandRegions) { if (stubIsland.start <= address && stubIsland.start + stubIsland.size > address) { @@ -1579,7 +1578,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) stubIsland.rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(stubIsland); + MutableState().regionsMappedIntoMemory.push_back(stubIsland); SaveToDSCView(); @@ -1590,7 +1589,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) } } - for (auto& dyldData : m_dyldDataRegions) + for (auto& dyldData : MutableState().dyldDataRegions) { if (dyldData.start <= address && dyldData.start + dyldData.size > address) { @@ -1618,7 +1617,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) dyldData.loaded = true; dyldData.rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(dyldData); + MutableState().regionsMappedIntoMemory.push_back(dyldData); SaveToDSCView(); @@ -1629,7 +1628,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) } } - for (auto& region : m_nonImageRegions) + for (auto& region : MutableState().nonImageRegions) { if (region.start <= address && region.start + region.size > address) { @@ -1656,7 +1655,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) region.loaded = true; region.rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(region); + MutableState().regionsMappedIntoMemory.push_back(region); SaveToDSCView(); @@ -1692,7 +1691,7 @@ bool SharedCache::LoadSectionAtAddress(uint64_t address) targetSegment->loaded = true; targetSegment->rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(*targetSegment); + MutableState().regionsMappedIntoMemory.push_back(*targetSegment); SaveToDSCView(); @@ -1716,12 +1715,14 @@ bool SharedCache::LoadImageWithInstallName(std::string installName) std::unique_lock<std::mutex> lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); DeserializeFromRawView(); + WillMutateState(); + m_logger->LogInfo("Loading image %s", installName.c_str()); auto vm = GetVMMap(); CacheImage* targetImage = nullptr; - for (auto& cacheImage : m_images) + for (auto& cacheImage : MutableState().images) { if (cacheImage.installName == installName) { @@ -1729,11 +1730,15 @@ bool SharedCache::LoadImageWithInstallName(std::string installName) break; } } - - auto header = m_headers[targetImage->headerLocation]; + auto it = State().headers.find(targetImage->headerLocation); + if (it == State().headers.end()) + { + return false; + } + const auto& header = it->second; auto id = m_dscView->BeginUndoActions(); - m_viewState = DSCViewStateLoadedWithImages; + MutableState().viewState = DSCViewStateLoadedWithImages; auto reader = VMReader(vm); reader.Seek(targetImage->headerLocation); @@ -1766,7 +1771,7 @@ bool SharedCache::LoadImageWithInstallName(std::string installName) region.loaded = true; region.rawViewOffsetIfLoaded = rawViewEnd; - m_regionsMappedIntoMemory.push_back(region); + MutableState().regionsMappedIntoMemory.push_back(region); m_dscView->GetParentView()->AddAutoSegment(rawViewEnd, region.size, rawViewEnd, region.size, region.flags); m_dscView->AddUserSegment(region.start, region.size, rawViewEnd, region.size, region.flags); @@ -2256,6 +2261,7 @@ std::optional<SharedCacheMachOHeader> SharedCache::LoadHeaderForAddress(std::sha void SharedCache::InitializeHeader( Ref<BinaryView> view, VM* vm, SharedCacheMachOHeader header, std::vector<MemoryRegion*> regionsToLoad) { + WillMutateState(); Ref<Settings> settings = view->GetLoadSettings(VIEW_NAME); bool applyFunctionStarts = true; @@ -2625,7 +2631,7 @@ void SharedCache::InitializeHeader( view->DefineAutoSymbol(symbolObj); symbolInfos.push_back({sym.n_value, {type, symbol}}); } - m_symbolInfos[header.textBase] = symbolInfos; + MutableState().symbolInfos[header.textBase] = symbolInfos; } if (header.exportTriePresent && header.linkeditPresent && vm->AddressIsMapped(header.linkeditSegment.vmaddr)) @@ -2671,7 +2677,7 @@ void SharedCache::InitializeHeader( else view->DefineAutoSymbol(symbol); } - m_exportInfos[header.textBase] = exportMapping; + MutableState().exportInfos[header.textBase] = std::move(exportMapping); } view->EndBulkModifySymbols(); @@ -2778,7 +2784,7 @@ std::vector<Ref<Symbol>> SharedCache::ParseExportTrie(std::shared_ptr<MMappedFil std::vector<std::string> SharedCache::GetAvailableImages() { std::vector<std::string> installNames; - for (const auto& header : m_headers) + for (const auto& header : State().headers) { installNames.push_back(header.second.installName); } @@ -2788,10 +2794,12 @@ std::vector<std::string> SharedCache::GetAvailableImages() std::vector<std::pair<std::string, Ref<Symbol>>> SharedCache::LoadAllSymbolsAndWait() { + WillMutateState(); + std::unique_lock<std::mutex> initialLoadBlock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); std::vector<std::pair<std::string, Ref<Symbol>>> symbols; - for (const auto& img : m_images) + for (const auto& img : State().images) { auto header = HeaderForAddress(img.headerLocation); std::shared_ptr<MMappedFileAccessor> mapping; @@ -2810,7 +2818,7 @@ std::vector<std::pair<std::string, Ref<Symbol>>> SharedCache::LoadAllSymbolsAndW exportMapping.push_back({sym->GetAddress(), {sym->GetType(), sym->GetRawName()}}); symbols.push_back({img.installName, sym}); } - m_exportInfos[header->textBase] = exportMapping; + MutableState().exportInfos[header->textBase] = std::move(exportMapping); } SaveToDSCView(); @@ -2832,17 +2840,22 @@ std::string SharedCache::SerializedImageHeaderForAddress(uint64_t address) std::string SharedCache::SerializedImageHeaderForName(std::string name) { - auto header = HeaderForAddress(m_imageStarts[name]); - if (header) + if (auto it = State().imageStarts.find(name); it != State().imageStarts.end()) { - return header->AsString(); + if (auto header = HeaderForAddress(it->second)) + { + return header->AsString(); + } } return ""; } -void SharedCache::FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis) +void SharedCache::FindSymbolAtAddrAndApplyToAddr( + uint64_t symbolLocation, uint64_t targetLocation, bool triggerReanalysis) { + WillMutateState(); + std::string prefix = ""; if (symbolLocation != targetLocation) prefix = "j_"; @@ -2929,7 +2942,7 @@ void SharedCache::FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64 } { std::unique_lock<std::mutex> _lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); - m_exportInfos[header->textBase] = exportMapping; + MutableState().exportInfos[header->textBase] = std::move(exportMapping); } m_dscView->EndBulkModifySymbols(); m_dscView->ForgetUndoActions(id); @@ -2944,22 +2957,16 @@ bool SharedCache::SaveToDSCView() auto data = AsMetadata(); m_dscView->StoreMetadata(SharedCacheMetadataTag, data); m_dscView->GetParentView()->GetParentView()->StoreMetadata(SharedCacheMetadataTag, data); + + // By moving our state the to cache we can avoid creating a copy in the case + // that no further mutations are made to `this`. If we're not done being mutated, + // the data will be copied on the first mutation. + auto cachedState = std::make_shared<struct State>(std::move(*m_state)); + m_state = cachedState; + m_stateIsShared = true; + std::unique_lock<std::recursive_mutex> viewStateCacheLock(viewStateMutex); - ViewStateCacheStore c; - c.m_imageStarts = m_imageStarts; - c.m_cacheFormat = m_cacheFormat; - c.m_backingCaches = m_backingCaches; - c.m_viewState = m_viewState; - c.m_headers = m_headers; - c.m_images = m_images; - c.m_regionsMappedIntoMemory = m_regionsMappedIntoMemory; - c.m_stubIslandRegions = m_stubIslandRegions; - c.m_dyldDataRegions = m_dyldDataRegions; - c.m_nonImageRegions = m_nonImageRegions; - c.m_baseFilePath = m_baseFilePath; - c.m_exportInfos = m_exportInfos; - c.m_symbolInfos = m_symbolInfos; - viewStateCache[m_dscView->GetFile()->GetSessionId()] = c; + viewStateCache[m_dscView->GetFile()->GetSessionId()] = std::move(cachedState); m_metadataValid = true; @@ -2970,7 +2977,7 @@ bool SharedCache::SaveToDSCView() std::vector<MemoryRegion> SharedCache::GetMappedRegions() const { std::unique_lock<std::mutex> lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); - return m_regionsMappedIntoMemory; + return State().regionsMappedIntoMemory; } extern "C" @@ -3116,7 +3123,7 @@ extern "C" { if (cache->object) { - return (BNDSCViewState)cache->object->State(); + return (BNDSCViewState)cache->object->ViewState(); } return BNDSCViewState::Unloaded; @@ -3323,14 +3330,14 @@ void SharedCache::Store(SerializationContext& context) const { Serialize(context, "metadataVersion", METADATA_VERSION); - MSS(m_viewState); - MSS_CAST(m_cacheFormat, uint8_t); - MSS(m_imageStarts); - MSS(m_baseFilePath); + Serialize(context, "m_viewState", State().viewState); + Serialize(context, "m_cacheFormat", State().cacheFormat); + Serialize(context, "m_imageStarts", State().imageStarts); + Serialize(context, "m_baseFilePath", State().baseFilePath); Serialize(context, "headers"); context.writer.StartArray(); - for (auto& [k, v] : m_headers) + for (auto& [k, v] : State().headers) { context.writer.StartObject(); v.Store(context); @@ -3340,7 +3347,7 @@ void SharedCache::Store(SerializationContext& context) const Serialize(context, "exportInfos"); context.writer.StartArray(); - for (const auto& pair1 : m_exportInfos) + for (const auto& pair1 : State().exportInfos) { context.writer.StartObject(); Serialize(context, "key", pair1.first); @@ -3359,12 +3366,12 @@ void SharedCache::Store(SerializationContext& context) const } context.writer.EndArray(); - Serialize(context, "backingCaches", m_backingCaches); - Serialize(context, "stubIslands", m_stubIslandRegions); - Serialize(context, "images", m_images); - Serialize(context, "regionsMappedIntoMemory", m_regionsMappedIntoMemory); - Serialize(context, "dyldDataSections", m_dyldDataRegions); - Serialize(context, "nonImageRegions", m_nonImageRegions); + Serialize(context, "backingCaches", State().backingCaches); + Serialize(context, "stubIslands", State().stubIslandRegions); + Serialize(context, "images", State().images); + Serialize(context, "regionsMappedIntoMemory", State().regionsMappedIntoMemory); + Serialize(context, "dyldDataSections", State().dyldDataRegions); + Serialize(context, "nonImageRegions", State().nonImageRegions); } void SharedCache::Load(DeserializationContext& context) @@ -3382,18 +3389,23 @@ void SharedCache::Load(DeserializationContext& context) m_logger->LogError("Shared Cache metadata version missing"); return; } - m_viewState = MSL_CAST(m_viewState, uint8_t, DSCViewState); - m_cacheFormat = MSL_CAST(m_cacheFormat, uint8_t, SharedCacheFormat); - m_headers.clear(); + + m_stateIsShared = false; + m_state = std::make_shared<struct SharedCache::State>(); + + MutableState().viewState = static_cast<DSCViewState>(context.load<uint8_t>("m_viewState")); + MutableState().cacheFormat = static_cast<SharedCacheFormat>(context.load<uint8_t>("m_cacheFormat")); + for (auto& startAndHeader : context.doc["headers"].GetArray()) { SharedCacheMachOHeader header; header.LoadFromValue(startAndHeader); - m_headers[header.textBase] = header; + MutableState().headers[header.textBase] = std::move(header); } - MSL(m_imageStarts); - MSL(m_baseFilePath); - m_exportInfos.clear(); + + Deserialize(context, "m_imageStarts", MutableState().imageStarts); + Deserialize(context, "m_baseFilePath", MutableState().baseFilePath); + for (const auto& obj1 : context.doc["exportInfos"].GetArray()) { std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>> innerVec; @@ -3404,9 +3416,9 @@ void SharedCache::Load(DeserializationContext& context) innerVec.push_back({obj2["key"].GetUint64(), innerPair}); } - m_exportInfos[obj1["key"].GetUint64()] = innerVec; + MutableState().exportInfos[obj1["key"].GetUint64()] = std::move(innerVec); } - m_symbolInfos.clear(); + for (auto& symbolInfo : context.doc["symbolInfos"].GetArray()) { std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>> symbolInfoVec; @@ -3415,52 +3427,94 @@ void SharedCache::Load(DeserializationContext& context) symbolInfoVec.push_back({symbolInfoPair[0].GetUint64(), {(BNSymbolType)symbolInfoPair[1].GetUint(), symbolInfoPair[2].GetString()}}); } - m_symbolInfos[symbolInfo[0].GetUint64()] = std::move(symbolInfoVec); + MutableState().symbolInfos[symbolInfo[0].GetUint64()] = std::move(symbolInfoVec); } - m_backingCaches.clear(); + for (auto& bcV : context.doc["backingCaches"].GetArray()) { BackingCache bc; bc.LoadFromValue(bcV); - m_backingCaches.push_back(std::move(bc)); + MutableState().backingCaches.push_back(std::move(bc)); } - m_images.clear(); + for (auto& imgV : context.doc["images"].GetArray()) { CacheImage img; img.LoadFromValue(imgV); - m_images.push_back(std::move(img)); + MutableState().images.push_back(std::move(img)); } - m_regionsMappedIntoMemory.clear(); + for (auto& rV : context.doc["regionsMappedIntoMemory"].GetArray()) { MemoryRegion r; r.LoadFromValue(rV); - m_regionsMappedIntoMemory.push_back(std::move(r)); + MutableState().regionsMappedIntoMemory.push_back(std::move(r)); } - m_stubIslandRegions.clear(); + for (auto& siV : context.doc["stubIslands"].GetArray()) { MemoryRegion si; si.LoadFromValue(siV); - m_stubIslandRegions.push_back(std::move(si)); + MutableState().stubIslandRegions.push_back(std::move(si)); } - m_dyldDataRegions.clear(); + for (auto& siV : context.doc["dyldDataSections"].GetArray()) { MemoryRegion si; si.LoadFromValue(siV); - m_dyldDataRegions.push_back(std::move(si)); + MutableState().dyldDataRegions.push_back(std::move(si)); } - m_nonImageRegions.clear(); + for (auto& siV : context.doc["nonImageRegions"].GetArray()) { MemoryRegion si; si.LoadFromValue(siV); - m_nonImageRegions.push_back(std::move(si)); + MutableState().nonImageRegions.push_back(std::move(si)); } m_metadataValid = true; } +__attribute__((always_inline)) void SharedCache::AssertMutable() const +{ + if (m_stateIsShared) + { + abort(); + } +} + +void SharedCache::WillMutateState() +{ + if (!m_state) + { + m_state = std::make_shared<struct State>(); + } + else if (m_stateIsShared) + { + m_state = std::make_shared<struct State>(*m_state); + } + m_stateIsShared = false; +} + + +const std::vector<BackingCache>& SharedCache::BackingCaches() const +{ + return State().backingCaches; +} + +DSCViewState SharedCache::ViewState() const +{ + return State().viewState; +} + +const std::unordered_map<std::string, uint64_t>& SharedCache::AllImageStarts() const +{ + return State().imageStarts; +} + +const std::unordered_map<uint64_t, SharedCacheMachOHeader>& SharedCache::AllImageHeaders() const +{ + return State().headers; +} + } // namespace SharedCacheCore |
