Skip to content

Commit 47cfa56

Browse files
committed
Improve MSVC VFT analysis speed and accuracy
Also adds more information to the progress text when processing vfts for both msvc and itanium
1 parent 315264b commit 47cfa56

File tree

2 files changed

+38
-48
lines changed

2 files changed

+38
-48
lines changed

plugins/rtti/itanium.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -816,14 +816,15 @@ void ItaniumRTTIProcessor::ProcessVFT()
816816
m_classInfo[coLocatorAddr] = classInfo;
817817
};
818818

819+
size_t processedNum = 0;
819820
for (const auto &[coLocatorAddr, vftAddrs]: vftMap)
820821
{
821822
if (bgTask->IsCancelled())
822823
break;
823824
for (const auto& vftAddr: vftAddrs)
824-
{
825825
populateVftEntries(coLocatorAddr, vftAddr);
826-
}
826+
std::string progress = fmt::format("Processing Itanium VFTs... {}/{}", processedNum++, vftMap.size());
827+
bgTask->SetProgressText(progress);
827828
}
828829

829830
bgTask->Finish();

plugins/rtti/microsoft.cpp

Lines changed: 35 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -695,9 +695,9 @@ void MicrosoftRTTIProcessor::ProcessRTTI()
695695

696696
void MicrosoftRTTIProcessor::ProcessVFT()
697697
{
698-
auto bgTask = new BackgroundTask("Scanning for Microsoft RTTI...", true);
698+
auto bgTask = new BackgroundTask("Scanning for Microsoft VFT...", true);
699699
std::map<uint64_t, uint64_t> vftMap = {};
700-
std::map<uint64_t, std::optional<VirtualFunctionTableInfo>> vftFinishedMap = {};
700+
std::unordered_set<uint64_t> vftFinished = {};
701701
auto start_time = std::chrono::high_resolution_clock::now();
702702
for (auto &[coLocatorAddr, classInfo]: m_classInfo)
703703
{
@@ -749,20 +749,34 @@ void MicrosoftRTTIProcessor::ProcessVFT()
749749
}
750750
}
751751

752-
auto GetCachedVFTInfo = [&](uint64_t vftAddr, ClassInfo& classInfo) -> std::optional<VirtualFunctionTableInfo> {
753-
// Check in the cache so that we don't process vfts more than once.
754-
auto cachedVftInfo = vftFinishedMap.find(vftAddr);
755-
if (cachedVftInfo != vftFinishedMap.end())
756-
return cachedVftInfo->second;
752+
std::function<void(uint64_t)> processClassAndBases = [&](uint64_t coLocatorAddr) -> void {
753+
auto& classInfo = m_classInfo[coLocatorAddr];
754+
uint64_t vftAddr = vftMap[coLocatorAddr];
755+
if (vftFinished.find(vftAddr) != vftFinished.end() || classInfo.vft.has_value())
756+
return;
757+
758+
// Process all relevant base classes first.
759+
// Otherwise, when we process this class we won't have the base vft available if needed.
760+
for (auto& baseInfo : classInfo.baseClasses)
761+
{
762+
for (auto& [baseCoLocAddr, baseClassInfo] : m_classInfo)
763+
{
764+
if (baseClassInfo.className != baseInfo.className)
765+
continue;
766+
processClassAndBases(baseCoLocAddr);
767+
// TODO: We might want to return the vft from processClassAndBases instead of doing this.
768+
baseInfo.vft = m_classInfo[baseCoLocAddr].vft;
769+
}
770+
}
771+
772+
// Process the vtable for the current class.
773+
// By this point all base classes should already exist, along with their type.
757774

758775
// Get the appropriate base class if there is one by reading the colocator.
759-
BinaryReader reader = BinaryReader(m_view);
760-
reader.Seek(vftAddr - m_view->GetAddressSize());
761-
auto coLocatorAddr = reader.ReadPointer();
762776
auto coLocator = ReadCompleteObjectorLocator(m_view, coLocatorAddr);
763777
// TODO: This should always be valid!
764778
if (!coLocator.has_value())
765-
return std::nullopt;
779+
return;
766780

767781
std::optional<BaseClassInfo> baseClassInfo;
768782
for (const auto& base: classInfo.baseClasses)
@@ -775,45 +789,20 @@ void MicrosoftRTTIProcessor::ProcessVFT()
775789
}
776790
}
777791

792+
vftFinished.insert(vftAddr);
778793
auto vftInfo = ProcessVFT(vftAddr, classInfo, baseClassInfo);
779-
vftFinishedMap[vftAddr] = vftInfo;
780-
return vftInfo;
794+
classInfo.vft = vftInfo.value();
781795
};
782796

783-
std::function<void(uint64_t)> ProcessClassAndBases = [&](uint64_t coLocatorAddr) -> void {
784-
auto& classInfo = m_classInfo[coLocatorAddr];
785-
786-
// Process all relevant base classes first.
787-
// Otherwise, when we process this class we won't have the base vft available if needed.
788-
for (auto& baseInfo : classInfo.baseClasses)
789-
{
790-
for (auto& [baseCoLocAddr, baseClassInfo] : m_classInfo)
791-
{
792-
if (baseClassInfo.className == baseInfo.className)
793-
{
794-
uint64_t baseVftAddr = vftMap[baseCoLocAddr];
795-
// Recurse into the bases bases.
796-
ProcessClassAndBases(baseCoLocAddr);
797-
798-
// Fetch the VFT info for the base class and store it.
799-
if (auto baseVftInfo = GetCachedVFTInfo(baseVftAddr, baseClassInfo))
800-
{
801-
baseInfo.vft = baseVftInfo.value();
802-
break;
803-
}
804-
}
805-
}
806-
}
807-
808-
// Process the vtable for the current class.
809-
// By this point all base classes should already exist, along with their type.
810-
uint64_t vftAddr = vftMap[coLocatorAddr];
811-
if (auto vftInfo = GetCachedVFTInfo(vftAddr, classInfo))
812-
classInfo.vft = vftInfo.value();
813-
};
814-
797+
size_t processedNum = 0;
815798
for (const auto &[coLocatorAddr, _]: vftMap)
816-
ProcessClassAndBases(coLocatorAddr);
799+
{
800+
if (bgTask->IsCancelled())
801+
break;
802+
processClassAndBases(coLocatorAddr);
803+
std::string progress = fmt::format("Processing Microsoft VFTs... {}/{}", processedNum++, vftMap.size());
804+
bgTask->SetProgressText(progress);
805+
}
817806

818807
bgTask->Finish();
819808
auto end_time = std::chrono::high_resolution_clock::now();

0 commit comments

Comments
 (0)