| 553 | |
| 554 | |
| 555 | std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVFT(uint64_t vftAddr, ClassInfo &classInfo, std::optional<BaseClassInfo> baseClassInfo) |
| 556 | { |
| 557 | VirtualFunctionTableInfo vftInfo = {vftAddr}; |
| 558 | BinaryReader reader = BinaryReader(m_view); |
| 559 | reader.Seek(vftAddr); |
| 560 | // Gather all virtual functions |
| 561 | std::vector<VirtualFunctionInfo> virtualFunctions = {}; |
| 562 | while (true) |
| 563 | { |
| 564 | uint64_t vFuncAddr = reader.ReadPointer(); |
| 565 | auto funcs = m_view->GetAnalysisFunctionsForAddress(vFuncAddr); |
| 566 | if (funcs.empty()) |
| 567 | { |
| 568 | Ref<Segment> segment = m_view->GetSegmentAt(vFuncAddr); |
| 569 | if (segment == nullptr || !(segment->GetFlags() & (SegmentExecutable | SegmentDenyWrite))) |
| 570 | { |
| 571 | // TODO: Sometimes vFunc idx will be zeroed iirc. |
| 572 | // We allow vfuncs to point to extern functions. |
| 573 | // TODO: Until https://github.com/Vector35/binaryninja-api/issues/5982 is fixed we need to check extern sym relocs instead of the symbol directly |
| 574 | auto vFuncSym = GetRealSymbol(m_view, reader.GetOffset(), vFuncAddr); |
| 575 | if (!vFuncSym) |
| 576 | break; |
| 577 | DataVariable dv; |
| 578 | bool foundDv = m_view->GetDataVariableAtAddress(vFuncAddr, dv); |
| 579 | // Last virtual function, or hit the next vtable. |
| 580 | if (!foundDv || !dv.type->m_object) |
| 581 | break; |
| 582 | // Void externs are very likely to be a func. |
| 583 | // TODO: Add some sanity checks for this! |
| 584 | if (!dv.type->IsFunction() && !(dv.type->IsVoid() && vFuncSym->GetType() == ExternalSymbol)) |
| 585 | break; |
| 586 | } |
| 587 | else |
| 588 | { |
| 589 | // TODO: Is likely a function check here? |
| 590 | m_logger->LogDebug("Discovered function from virtual function table... %llx", vFuncAddr); |
| 591 | m_view->AddFunctionForAnalysis(m_view->GetDefaultPlatform(), vFuncAddr, true); |
| 592 | } |
| 593 | } |
| 594 | // Only ever add one function. |
| 595 | virtualFunctions.emplace_back(VirtualFunctionInfo{vFuncAddr}); |
| 596 | } |
| 597 | |
| 598 | if (virtualFunctions.empty()) |
| 599 | { |
| 600 | m_logger->LogDebug("Skipping empty virtual function table... %llx", vftAddr); |
| 601 | return std::nullopt; |
| 602 | } |
| 603 | |
| 604 | // Create virtual function table type |
| 605 | auto vftTypeName = fmt::format("{}::VTable", classInfo.className); |
| 606 | if (baseClassInfo.has_value()) |
| 607 | { |
| 608 | // TODO: What is the correct form for the name? |
| 609 | vftTypeName = fmt::format("{}::{}", baseClassInfo->className, vftTypeName); |
| 610 | } |
| 611 | // TODO: Hack the debug type id is used here to allow the PDB type (debug info) to overwrite the RTTI vtable type. |
| 612 | auto typeId = Type::GenerateAutoDebugTypeId(vftTypeName); |
no test coverage detected