Skip to content

Commit 8953660

Browse files
WeiN76LQh0cyn
authored andcommitted
[SharedCache] Use m_exportInfos as an export list cache
`SharedCache::ParseExportTrie` is getting called a lot during DSC library loading and analysis. In large part due to the hot path `SharedCache::FindSymbolAtAddrAndApplyToAddr`. Its unnecessary for it to be being called more than once per DSC header as the export list symbol information is stored in `SharedCache::m_exportInfos`. This commit adds the function `SharedCache::GetExportListForHeader`, which will either return the header's list of symbol information cached in `SharedCache::m_exportInfos` or call `SharedCache::ParseExportTrie` and cache the results in `SharedCache::m_exportInfos`. This should also improve the execution time of `SharedCache::LoadAllSymbolsAndWait`. Further improvement here would be to add locking to `SharedCache::GetExportListForHeader` so that races don't result in redundant parsing of the export trie for the same header if multiple threads call `SharedCache::GetExportListForHeader` at the same time for the same header. This only really matters during initial loading because from what I can tell that parses all the export trie's anyway.
1 parent 1bf8980 commit 8953660

File tree

2 files changed

+78
-49
lines changed

2 files changed

+78
-49
lines changed

view/sharedcache/core/SharedCache.cpp

Lines changed: 75 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,33 +2665,34 @@ void SharedCache::InitializeHeader(
26652665

26662666
if (header.exportTriePresent && header.linkeditPresent && vm->AddressIsMapped(header.linkeditSegment.vmaddr))
26672667
{
2668-
auto symbols = SharedCache::ParseExportTrie(vm->MappingAtAddress(header.linkeditSegment.vmaddr).first.fileAccessor->lock(), header);
2669-
std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>> exportMapping;
2668+
auto symbols = GetExportListForHeader(header, [&]() {
2669+
return vm->MappingAtAddress(header.linkeditSegment.vmaddr).first.fileAccessor->lock();
2670+
});
26702671
for (const auto& symbol : symbols)
26712672
{
2672-
exportMapping.push_back({symbol->GetAddress(), {symbol->GetType(), symbol->GetRawName()}});
2673+
auto bnSymbol = new Symbol(symbol.second.first, symbol.second.second, symbol.first);
26732674
if (typeLib)
26742675
{
2675-
auto type = m_dscView->ImportTypeLibraryObject(typeLib, {symbol->GetFullName()});
2676+
auto type = m_dscView->ImportTypeLibraryObject(typeLib, {symbol.second.second});
26762677

26772678
if (type)
26782679
{
2679-
view->DefineAutoSymbolAndVariableOrFunction(view->GetDefaultPlatform(), symbol, type);
2680+
view->DefineAutoSymbolAndVariableOrFunction(view->GetDefaultPlatform(), bnSymbol, type);
26802681
}
26812682
else
2682-
view->DefineAutoSymbol(symbol);
2683+
view->DefineAutoSymbol(bnSymbol);
26832684

2684-
if (view->GetAnalysisFunction(view->GetDefaultPlatform(), symbol->GetAddress()))
2685+
if (view->GetAnalysisFunction(view->GetDefaultPlatform(), symbol.first))
26852686
{
2686-
auto func = view->GetAnalysisFunction(view->GetDefaultPlatform(), symbol->GetAddress());
2687-
if (symbol->GetFullName() == "_objc_msgSend")
2687+
auto func = view->GetAnalysisFunction(view->GetDefaultPlatform(), symbol.first);
2688+
if (symbol.second.second == "_objc_msgSend")
26882689
{
26892690
func->SetHasVariableArguments(false);
26902691
}
2691-
else if (symbol->GetFullName().find("_objc_retain_x") != std::string::npos || symbol->GetFullName().find("_objc_release_x") != std::string::npos)
2692+
else if (symbol.second.second.find("_objc_retain_x") != std::string::npos || symbol.second.second.find("_objc_release_x") != std::string::npos)
26922693
{
2693-
auto x = symbol->GetFullName().rfind("x");
2694-
auto num = symbol->GetFullName().substr(x + 1);
2694+
auto x = symbol.second.second.rfind("x");
2695+
auto num = symbol.second.second.substr(x + 1);
26952696

26962697
std::vector<BinaryNinja::FunctionParameter> callTypeParams;
26972698
auto cc = m_dscView->GetDefaultArchitecture()->GetCallingConventionByName("apple-arm64-objc-fast-arc-" + num);
@@ -2704,9 +2705,8 @@ void SharedCache::InitializeHeader(
27042705
}
27052706
}
27062707
else
2707-
view->DefineAutoSymbol(symbol);
2708+
view->DefineAutoSymbol(bnSymbol);
27082709
}
2709-
MutableState().exportInfos[header.textBase] = std::move(exportMapping);
27102710
}
27112711
view->EndBulkModifySymbols();
27122712

@@ -2794,6 +2794,7 @@ std::vector<Ref<Symbol>> SharedCache::ParseExportTrie(std::shared_ptr<MMappedFil
27942794

27952795
try
27962796
{
2797+
// FIXME we can absolutely predict this size
27972798
std::vector<Ref<Symbol>> symbols;
27982799
auto [begin, end] = linkeditFile->ReadSpan(header.exportTrie.dataoff, header.exportTrie.datasize);
27992800
ReadExportNode(symbols, header, begin, end, begin, header.textBase, "");
@@ -2806,6 +2807,32 @@ std::vector<Ref<Symbol>> SharedCache::ParseExportTrie(std::shared_ptr<MMappedFil
28062807
}
28072808
}
28082809

2810+
2811+
std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>> SharedCache::GetExportListForHeader(SharedCacheMachOHeader header, std::function<std::shared_ptr<MMappedFileAccessor>()> provideLinkeditFile)
2812+
{
2813+
if (auto it = m_state->exportInfos.find(header.textBase); it != m_state->exportInfos.end())
2814+
{
2815+
return it->second;
2816+
}
2817+
else
2818+
{
2819+
// TODO does this have to be a functor? can't we just pass the accessor? if not, why?
2820+
std::shared_ptr<MMappedFileAccessor> linkeditFile = provideLinkeditFile();
2821+
if (!linkeditFile)
2822+
return std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>>();
2823+
2824+
auto exportList = SharedCache::ParseExportTrie(linkeditFile, header);
2825+
std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>> exportMapping(exportList.size());
2826+
for (const auto& sym : exportList)
2827+
{
2828+
exportMapping.push_back({sym->GetAddress(), {sym->GetType(), sym->GetRawName()}});
2829+
}
2830+
m_state->exportInfos[header.textBase] = exportMapping;
2831+
return exportMapping;
2832+
}
2833+
}
2834+
2835+
28092836
std::vector<std::string> SharedCache::GetAvailableImages()
28102837
{
28112838
std::vector<std::string> installNames;
@@ -2823,30 +2850,32 @@ std::vector<std::pair<std::string, Ref<Symbol>>> SharedCache::LoadAllSymbolsAndW
28232850

28242851
std::lock_guard initialLoadBlock(m_viewSpecificState->viewOperationsThatInfluenceMetadataMutex);
28252852

2853+
bool doSave = false;
28262854
std::vector<std::pair<std::string, Ref<Symbol>>> symbols;
28272855
for (const auto& img : State().images)
28282856
{
28292857
auto header = HeaderForAddress(img.headerLocation);
2830-
std::shared_ptr<MMappedFileAccessor> mapping;
2831-
try {
2832-
mapping = MMappedFileAccessor::Open(m_dscView, m_dscView->GetFile()->GetSessionId(), header->exportTriePath)->lock();
2833-
}
2834-
catch (...)
2835-
{
2836-
m_logger->LogWarn("Serious Error: Failed to open export trie %s for %s", header->exportTriePath.c_str(), header->installName.c_str());
2837-
continue;
2838-
}
2839-
auto exportList = SharedCache::ParseExportTrie(mapping, *header);
2840-
std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>> exportMapping;
2858+
auto exportList = GetExportListForHeader(*header, [&]() {
2859+
try {
2860+
auto mapping = MMappedFileAccessor::Open(m_dscView, m_dscView->GetFile()->GetSessionId(), header->exportTriePath)->lock();
2861+
doSave = true;
2862+
return mapping;
2863+
}
2864+
catch (...)
2865+
{
2866+
m_logger->LogWarn("Serious Error: Failed to open export trie %s for %s", header->exportTriePath.c_str(), header->installName.c_str());
2867+
return std::shared_ptr<MMappedFileAccessor>(nullptr);
2868+
}
2869+
});
28412870
for (const auto& sym : exportList)
28422871
{
2843-
exportMapping.push_back({sym->GetAddress(), {sym->GetType(), sym->GetRawName()}});
2844-
symbols.push_back({img.installName, sym});
2872+
symbols.push_back({img.installName, new Symbol(sym.second.first, sym.second.second, sym.first)});
28452873
}
2846-
MutableState().exportInfos[header->textBase] = std::move(exportMapping);
28472874
}
28482875

2849-
SaveToDSCView();
2876+
// Only save to DSC view if a header was actually loaded
2877+
if (doSave)
2878+
SaveToDSCView();
28502879

28512880
return symbols;
28522881
}
@@ -2926,41 +2955,42 @@ void SharedCache::FindSymbolAtAddrAndApplyToAddr(
29262955
auto header = HeaderForAddress(symbolLocation);
29272956
if (header)
29282957
{
2929-
std::shared_ptr<MMappedFileAccessor> mapping;
2930-
try {
2931-
mapping = MMappedFileAccessor::Open(m_dscView, m_dscView->GetFile()->GetSessionId(), header->exportTriePath)->lock();
2932-
}
2933-
catch (...)
2934-
{
2935-
m_logger->LogWarn("Serious Error: Failed to open export trie for %s", header->installName.c_str());
2936-
return;
2937-
}
2938-
auto exportList = SharedCache::ParseExportTrie(mapping, *header);
2958+
2959+
auto exportList = GetExportListForHeader(*header, [&]() {
2960+
try {
2961+
return MMappedFileAccessor::Open(m_dscView, m_dscView->GetFile()->GetSessionId(), header->exportTriePath)->lock();
2962+
}
2963+
catch (...)
2964+
{
2965+
m_logger->LogWarn("Serious Error: Failed to open export trie %s for %s", header->exportTriePath.c_str(), header->installName.c_str());
2966+
return std::shared_ptr<MMappedFileAccessor>(nullptr);
2967+
}
2968+
});
2969+
29392970
std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>> exportMapping;
29402971
auto typeLib = TypeLibraryForImage(header->installName);
29412972
id = m_dscView->BeginUndoActions();
29422973
m_dscView->BeginBulkModifySymbols();
29432974
for (const auto& sym : exportList)
29442975
{
2945-
exportMapping.push_back({sym->GetAddress(), {sym->GetType(), sym->GetRawName()}});
2946-
if (sym->GetAddress() == symbolLocation)
2976+
if (sym.first == symbolLocation)
29472977
{
29482978
if (auto func = m_dscView->GetAnalysisFunction(m_dscView->GetDefaultPlatform(), targetLocation))
29492979
{
29502980
m_dscView->DefineUserSymbol(
2951-
new Symbol(FunctionSymbol, prefix + sym->GetFullName(), targetLocation));
2981+
new Symbol(FunctionSymbol, prefix + sym.second.second, targetLocation));
29522982

29532983
if (typeLib)
2954-
if (auto type = m_dscView->ImportTypeLibraryObject(typeLib, {sym->GetFullName()}))
2984+
if (auto type = m_dscView->ImportTypeLibraryObject(typeLib, {sym.second.second}))
29552985
func->SetUserType(type);
29562986
}
29572987
else
29582988
{
29592989
m_dscView->DefineUserSymbol(
2960-
new Symbol(sym->GetType(), prefix + sym->GetFullName(), targetLocation));
2990+
new Symbol(sym.second.first, prefix + sym.second.second, targetLocation));
29612991

29622992
if (typeLib)
2963-
if (auto type = m_dscView->ImportTypeLibraryObject(typeLib, {sym->GetFullName()}))
2993+
if (auto type = m_dscView->ImportTypeLibraryObject(typeLib, {sym.second.second}))
29642994
m_dscView->DefineUserDataVariable(targetLocation, type);
29652995
}
29662996
if (triggerReanalysis)
@@ -2972,10 +3002,6 @@ void SharedCache::FindSymbolAtAddrAndApplyToAddr(
29723002
break;
29733003
}
29743004
}
2975-
{
2976-
std::lock_guard lock(m_viewSpecificState->viewOperationsThatInfluenceMetadataMutex);
2977-
MutableState().exportInfos[header->textBase] = std::move(exportMapping);
2978-
}
29793005
m_dscView->EndBulkModifySymbols();
29803006
m_dscView->ForgetUndoActions(id);
29813007
}

view/sharedcache/core/SharedCache.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,9 @@ namespace SharedCacheCore {
642642
std::vector<Ref<Symbol>> ParseExportTrie(
643643
std::shared_ptr<MMappedFileAccessor> linkeditFile, const SharedCacheMachOHeader& header);
644644

645+
std::vector<std::pair<uint64_t, std::pair<BNSymbolType, std::string>>> GetExportListForHeader(
646+
SharedCacheMachOHeader header, std::function<std::shared_ptr<MMappedFileAccessor>()> provideLinkeditFile);
647+
645648
Ref<TypeLibrary> TypeLibraryForImage(const std::string& installName);
646649

647650
size_t GetBaseAddress() const;

0 commit comments

Comments
 (0)