| 468 | |
| 469 | |
| 470 | std::optional<VirtualFunctionTableInfo> MicrosoftRTTIProcessor::ProcessVFT(uint64_t vftAddr, ClassInfo &classInfo, std::optional<BaseClassInfo> baseClassInfo) |
| 471 | { |
| 472 | VirtualFunctionTableInfo vftInfo = {vftAddr}; |
| 473 | // Gather all virtual functions |
| 474 | BinaryReader reader = BinaryReader(m_view); |
| 475 | reader.Seek(vftAddr); |
| 476 | // Virtual functions and the analysis object of it, if it exists. |
| 477 | std::vector<std::pair<uint64_t, std::optional<Ref<Function>>>> virtualFunctions = {}; |
| 478 | while (true) |
| 479 | { |
| 480 | uint64_t vFuncAddr = reader.ReadPointer(); |
| 481 | auto funcs = m_view->GetAnalysisFunctionsForAddress(vFuncAddr); |
| 482 | if (funcs.empty()) |
| 483 | { |
| 484 | Ref<Segment> segment = m_view->GetSegmentAt(vFuncAddr); |
| 485 | if (segment == nullptr || !(segment->GetFlags() & (SegmentExecutable | SegmentDenyWrite))) |
| 486 | { |
| 487 | // Last CompleteObjectLocator or hit the next CompleteObjectLocator |
| 488 | break; |
| 489 | } |
| 490 | // TODO: Is likely a function check here? |
| 491 | m_logger->LogDebug("Discovered function from virtual function table... %llx", vFuncAddr); |
| 492 | auto vFunc = m_view->AddFunctionForAnalysis(m_view->GetDefaultPlatform(), vFuncAddr, true); |
| 493 | virtualFunctions.emplace_back(vFuncAddr, vFunc ? std::optional(vFunc) : std::nullopt); |
| 494 | } |
| 495 | else |
| 496 | { |
| 497 | // Only ever add one function. |
| 498 | virtualFunctions.emplace_back(vFuncAddr, funcs.front()); |
| 499 | } |
| 500 | } |
| 501 | |
| 502 | if (virtualFunctions.empty()) |
| 503 | { |
| 504 | m_logger->LogDebug("Skipping empty virtual function table... %llx", vftAddr); |
| 505 | return std::nullopt; |
| 506 | } |
| 507 | |
| 508 | for (auto &[vFuncAddr, _]: virtualFunctions) |
| 509 | vftInfo.virtualFunctions.emplace_back(VirtualFunctionInfo{vFuncAddr}); |
| 510 | |
| 511 | // Create virtual function table type |
| 512 | auto vftTypeName = fmt::format("{}::VTable", classInfo.className); |
| 513 | if (baseClassInfo.has_value()) |
| 514 | { |
| 515 | // TODO: What is the correct form for the name? |
| 516 | vftTypeName = fmt::format("{}::{}", baseClassInfo->className, vftTypeName); |
| 517 | } |
| 518 | // TODO: Hack the debug type id is used here to allow the PDB type (debug info) to overwrite the RTTI vtable type. |
| 519 | auto typeId = Type::GenerateAutoDebugTypeId(vftTypeName); |
| 520 | Ref<Type> vftType = m_view->GetTypeById(typeId); |
| 521 | |
| 522 | if (vftType == nullptr) |
| 523 | { |
| 524 | size_t addrSize = m_view->GetAddressSize(); |
| 525 | StructureBuilder vftBuilder = {}; |
| 526 | vftBuilder.SetPropagateDataVariableReferences(true); |
| 527 | size_t vFuncIdx = 0; |
nothing calls this directly
no test coverage detected