diff --git a/view/sharedcache/core/SharedCache.cpp b/view/sharedcache/core/SharedCache.cpp index a7c7ffb01..ca8c9592d 100644 --- a/view/sharedcache/core/SharedCache.cpp +++ b/view/sharedcache/core/SharedCache.cpp @@ -71,7 +71,7 @@ struct ViewStateCacheStore { std::string m_baseFilePath; - std::unordered_map>>> m_exportInfos; + std::unordered_map>>> m_exportInfos; std::unordered_map>>> m_symbolInfos; }; @@ -2634,48 +2634,51 @@ void SharedCache::InitializeHeader( if (header.exportTriePresent && header.linkeditPresent && vm->AddressIsMapped(header.linkeditSegment.vmaddr)) { - auto symbols = SharedCache::ParseExportTrie(vm->MappingAtAddress(header.linkeditSegment.vmaddr).first.fileAccessor->lock(), header); - std::vector>> exportMapping; - for (const auto& symbol : symbols) + auto symbols = GetExportListForHeader(header, [&]() { + return vm->MappingAtAddress(header.linkeditSegment.vmaddr).first.fileAccessor->lock(); + }); + if (symbols) { - exportMapping.push_back({symbol->GetAddress(), {symbol->GetType(), symbol->GetRawName()}}); - if (typeLib) + for (const auto& [symbolAddress, symbol] : *symbols) { - auto type = m_dscView->ImportTypeLibraryObject(typeLib, {symbol->GetFullName()}); - - if (type) + if (typeLib) { - view->DefineAutoSymbolAndVariableOrFunction(view->GetDefaultPlatform(), symbol, type); - } - else - view->DefineAutoSymbol(symbol); + auto type = m_dscView->ImportTypeLibraryObject(typeLib, symbol->GetRawName()); - if (view->GetAnalysisFunction(view->GetDefaultPlatform(), symbol->GetAddress())) - { - auto func = view->GetAnalysisFunction(view->GetDefaultPlatform(), symbol->GetAddress()); - if (symbol->GetFullName() == "_objc_msgSend") + if (type) { - func->SetHasVariableArguments(false); + view->DefineAutoSymbolAndVariableOrFunction(view->GetDefaultPlatform(), symbol, type); } - else if (symbol->GetFullName().find("_objc_retain_x") != std::string::npos || symbol->GetFullName().find("_objc_release_x") != std::string::npos) + else + view->DefineAutoSymbol(symbol); + + if (view->GetAnalysisFunction(view->GetDefaultPlatform(), symbolAddress)) { - auto x = symbol->GetFullName().rfind("x"); - auto num = symbol->GetFullName().substr(x + 1); + auto func = view->GetAnalysisFunction(view->GetDefaultPlatform(), symbolAddress); + auto name = symbol->GetFullName(); + if (name == "_objc_msgSend") + { + func->SetHasVariableArguments(false); + } + else if (name.find("_objc_retain_x") != std::string::npos || name.find("_objc_release_x") != std::string::npos) + { + auto x = name.rfind("x"); + auto num = name.substr(x + 1); - std::vector callTypeParams; - auto cc = m_dscView->GetDefaultArchitecture()->GetCallingConventionByName("apple-arm64-objc-fast-arc-" + num); + std::vector callTypeParams; + auto cc = m_dscView->GetDefaultArchitecture()->GetCallingConventionByName("apple-arm64-objc-fast-arc-" + num); - callTypeParams.push_back({"obj", m_dscView->GetTypeByName({ "id" }), true, BinaryNinja::Variable()}); + callTypeParams.push_back({"obj", m_dscView->GetTypeByName({ "id" }), true, BinaryNinja::Variable()}); - auto funcType = BinaryNinja::Type::FunctionType(m_dscView->GetTypeByName({ "id" }), cc, callTypeParams); - func->SetUserType(funcType); + auto funcType = BinaryNinja::Type::FunctionType(m_dscView->GetTypeByName({ "id" }), cc, callTypeParams); + func->SetUserType(funcType); + } } } + else + view->DefineAutoSymbol(symbol); } - else - view->DefineAutoSymbol(symbol); } - m_exportInfos[header.textBase] = exportMapping; } view->EndBulkModifySymbols(); @@ -2779,6 +2782,39 @@ std::vector> SharedCache::ParseExportTrie(std::shared_ptr>> SharedCache::GetExportListForHeader(SharedCacheMachOHeader header, std::function()> provideLinkeditFile, bool* didModifyExportList) +{ + if (auto it = m_exportInfos.find(header.textBase); it != m_exportInfos.end()) + { + if (didModifyExportList) + *didModifyExportList = false; + return it->second; + } + else + { + std::shared_ptr linkeditFile = provideLinkeditFile(); + if (!linkeditFile) + { + if (didModifyExportList) + *didModifyExportList = false; + return nullptr; + } + + auto exportList = SharedCache::ParseExportTrie(linkeditFile, header); + auto exportMapping = std::make_shared>>(exportList.size()); + for (const auto& sym : exportList) + { + exportMapping->insert_or_assign(sym->GetAddress(), sym); + } + m_exportInfos.emplace(header.textBase, exportMapping); + if (didModifyExportList) + *didModifyExportList = true; + return m_exportInfos[header.textBase]; + } +} + + std::vector SharedCache::GetAvailableImages() { std::vector installNames; @@ -2794,30 +2830,33 @@ std::vector>> SharedCache::LoadAllSymbolsAndW { std::unique_lock initialLoadBlock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); + bool doSave = false; std::vector>> symbols; for (const auto& img : m_images) { auto header = HeaderForAddress(img.headerLocation); - std::shared_ptr mapping; - try { - mapping = MMappedFileAccessor::Open(m_dscView, m_dscView->GetFile()->GetSessionId(), header->exportTriePath)->lock(); - } - catch (...) - { - m_logger->LogWarn("Serious Error: Failed to open export trie %s for %s", header->exportTriePath.c_str(), header->installName.c_str()); + auto exportList = GetExportListForHeader(*header, [&]() { + try { + auto mapping = MMappedFileAccessor::Open(m_dscView, m_dscView->GetFile()->GetSessionId(), header->exportTriePath)->lock(); + return mapping; + } + catch (...) + { + m_logger->LogWarn("Serious Error: Failed to open export trie %s for %s", header->exportTriePath.c_str(), header->installName.c_str()); + return std::shared_ptr(nullptr); + } + }, &doSave); + if (!exportList) continue; - } - auto exportList = SharedCache::ParseExportTrie(mapping, *header); - std::vector>> exportMapping; - for (const auto& sym : exportList) + for (const auto& [_, symbol] : *exportList) { - exportMapping.push_back({sym->GetAddress(), {sym->GetType(), sym->GetRawName()}}); - symbols.push_back({img.installName, sym}); + symbols.push_back({img.installName, symbol}); } - m_exportInfos[header->textBase] = exportMapping; } - SaveToDSCView(); + // Only save to DSC view if a header was actually loaded + if (doSave) + SaveToDSCView(); return symbols; } @@ -2874,17 +2913,6 @@ void SharedCache::FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64 auto header = HeaderForAddress(symbolLocation); if (header) { - std::shared_ptr mapping; - try { - mapping = MMappedFileAccessor::Open(m_dscView, m_dscView->GetFile()->GetSessionId(), header->exportTriePath)->lock(); - } - catch (...) - { - m_logger->LogWarn("Serious Error: Failed to open export trie for %s", header->installName.c_str()); - return; - } - auto exportList = SharedCache::ParseExportTrie(mapping, *header); - std::vector>> exportMapping; std::unique_lock lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].typeLibraryLookupAndApplicationMutex); auto typeLib = m_dscView->GetTypeLibrary(header->installName); if (!typeLib) @@ -2897,46 +2925,54 @@ void SharedCache::FindSymbolAtAddrAndApplyToAddr(uint64_t symbolLocation, uint64 } } lock.unlock(); - id = m_dscView->BeginUndoActions(); - m_dscView->BeginBulkModifySymbols(); - for (const auto& sym : exportList) + + auto exportList = GetExportListForHeader(*header, [&]() { + try { + return MMappedFileAccessor::Open(m_dscView, m_dscView->GetFile()->GetSessionId(), header->exportTriePath)->lock(); + } + catch (...) + { + m_logger->LogWarn("Serious Error: Failed to open export trie %s for %s", header->exportTriePath.c_str(), header->installName.c_str()); + return std::shared_ptr(nullptr); + } + }); + + if (exportList) { - exportMapping.push_back({sym->GetAddress(), {sym->GetType(), sym->GetRawName()}}); - if (sym->GetAddress() == symbolLocation) + if (auto it = exportList->find(symbolLocation); it != exportList->end()) { - if (auto func = m_dscView->GetAnalysisFunction(m_dscView->GetDefaultPlatform(), targetLocation)) + id = m_dscView->BeginUndoActions(); + m_dscView->BeginBulkModifySymbols(); + + auto func = m_dscView->GetAnalysisFunction(m_dscView->GetDefaultPlatform(), targetLocation); + if (func) { m_dscView->DefineUserSymbol( - new Symbol(FunctionSymbol, prefix + sym->GetFullName(), targetLocation)); + new Symbol(FunctionSymbol, prefix + it->second->GetFullName(), targetLocation)); if (typeLib) - if (auto type = m_dscView->ImportTypeLibraryObject(typeLib, {sym->GetFullName()})) + if (auto type = m_dscView->ImportTypeLibraryObject(typeLib, {it->second->GetFullName()})) func->SetUserType(type); } else { m_dscView->DefineUserSymbol( - new Symbol(sym->GetType(), prefix + sym->GetFullName(), targetLocation)); + new Symbol(it->second->GetType(), prefix + it->second->GetFullName(), targetLocation)); if (typeLib) - if (auto type = m_dscView->ImportTypeLibraryObject(typeLib, {sym->GetFullName()})) + if (auto type = m_dscView->ImportTypeLibraryObject(typeLib, {it->second->GetFullName()})) m_dscView->DefineUserDataVariable(targetLocation, type); } if (triggerReanalysis) { - auto func = m_dscView->GetAnalysisFunction(m_dscView->GetDefaultPlatform(), targetLocation); if (func) func->Reanalyze(); } - break; + + m_dscView->EndBulkModifySymbols(); + m_dscView->ForgetUndoActions(id); } } - { - std::unique_lock _lock(viewSpecificMutexes[m_dscView->GetFile()->GetSessionId()].viewOperationsThatInfluenceMetadataMutex); - m_exportInfos[header->textBase] = exportMapping; - } - m_dscView->EndBulkModifySymbols(); - m_dscView->ForgetUndoActions(id); } } diff --git a/view/sharedcache/core/SharedCache.h b/view/sharedcache/core/SharedCache.h index 81c026203..a956adde9 100644 --- a/view/sharedcache/core/SharedCache.h +++ b/view/sharedcache/core/SharedCache.h @@ -956,20 +956,20 @@ namespace SharedCacheCore { // std::vector>>>> exportInfos; rapidjson::Document exportInfos(rapidjson::kArrayType); - for (const auto& pair1 : m_exportInfos) + for (const auto& [headerAddress, symbolMap] : m_exportInfos) { rapidjson::Value subObj(rapidjson::kObjectType); rapidjson::Value subArr(rapidjson::kArrayType); - for (const auto& pair2 : pair1.second) + for (const auto& [symbolAddress, symbol] : *symbolMap) { rapidjson::Value subSubObj(rapidjson::kObjectType); - subSubObj.AddMember("key", pair2.first, m_activeContext.allocator); - subSubObj.AddMember("val1", pair2.second.first, m_activeContext.allocator); - subSubObj.AddMember("val2", pair2.second.second, m_activeContext.allocator); + subSubObj.AddMember("key", symbolAddress, m_activeContext.allocator); + subSubObj.AddMember("val1", symbol->GetType(), m_activeContext.allocator); + subSubObj.AddMember("val2", symbol->GetRawName(), m_activeContext.allocator); subArr.PushBack(subSubObj, m_activeContext.allocator); } - subObj.AddMember("key", pair1.first, m_activeContext.allocator); + subObj.AddMember("key", headerAddress, m_activeContext.allocator); subObj.AddMember("value", subArr, m_activeContext.allocator); exportInfos.PushBack(subObj, m_activeContext.allocator); @@ -1042,14 +1042,15 @@ namespace SharedCacheCore { m_exportInfos.clear(); for (const auto& obj1 : m_activeDeserContext.doc["exportInfos"].GetArray()) { - std::vector>> innerVec; + auto innerMap = std::make_shared>>(); for (const auto& obj2 : obj1["value"].GetArray()) { - std::pair innerPair = { (BNSymbolType)obj2["val1"].GetUint64(), obj2["val2"].GetString() }; - innerVec.push_back({ obj2["key"].GetUint64(), innerPair }); + auto address = obj2["key"].GetUint64(); + Ref symbol = new Symbol((BNSymbolType)obj2["val1"].GetUint64(), obj2["val2"].GetString(), address); + innerMap->insert_or_assign(address, symbol); } - m_exportInfos[obj1["key"].GetUint64()] = innerVec; + m_exportInfos.emplace(obj1["key"].GetUint64(), innerMap); } m_symbolInfos.clear(); for (auto& symbolInfo : m_activeDeserContext.doc["symbolInfos"].GetArray()) @@ -1114,8 +1115,7 @@ namespace SharedCacheCore { // Updated as the view is loaded further, more images are added, etc DSCViewState m_viewState = DSCViewStateUnloaded; - std::unordered_map>>> - m_exportInfos; + std::unordered_map>>> m_exportInfos; std::unordered_map>>> m_symbolInfos; // --- @@ -1196,6 +1196,7 @@ namespace SharedCacheCore { const std::string& currentText, size_t cursor, uint32_t endGuard); std::vector> ParseExportTrie( std::shared_ptr linkeditFile, SharedCacheMachOHeader header); + std::shared_ptr>> GetExportListForHeader(SharedCacheMachOHeader header, std::function()> provideLinkeditFile, bool* didModifyExportList = nullptr); };