@@ -16,16 +16,10 @@ TypeInfo::TypeInfo(BinaryView *view, uint64_t address)
1616 reader.Seek (address);
1717 base = reader.ReadPointer ();
1818 auto typeNameAddr = reader.ReadPointer ();
19+ if (!view->IsValidOffset (typeNameAddr))
20+ return ;
1921 reader.Seek (typeNameAddr);
20- // For the sake of my sanity we just do this...
21- try
22- {
23- type_name = reader.ReadCString (512 );
24- }
25- catch (std::exception& e)
26- {
27- type_name = " " ;
28- }
22+ type_name = reader.ReadCString (512 );
2923}
3024
3125
@@ -276,22 +270,21 @@ std::optional<BaseClassInfo> ItaniumRTTIProcessor::ProcessVFTBaseClassInfo(uint6
276270 reader.Seek (vftAddr - 0x10 );
277271
278272 auto adjustmentOffset = static_cast <int32_t >(reader.Read32 ());
279- [[maybe_unused]]
280- auto _what = static_cast <int32_t >(reader.Read32 ());
273+ auto baseIdx = static_cast <int32_t >(reader.Read32 ());
281274 uint64_t classOffset = std::abs (adjustmentOffset);
282275
283276 std::optional<BaseClassInfo> selectedBaseClassInfo = std::nullopt ;
284277 // Assuming we do not have a baseClassInfo already passed we can deduce it here.
285278 for (auto & baseClass : classInfo.baseClasses )
286279 {
287- if (baseClass.offset == 0 )
288- {
289- // If the base class is at offset 0 that means it has yet to be adjusted.
290- // NOTE: This should only happen for `TIVSIClass`. If this assigns more than
291- // one base class to this offset we are screwed.
292- baseClass.offset = classOffset;
293- LogInfo (" Adjusting base class offset for %llx to %llx" , vftAddr, classOffset);
294- }
280+ // if (baseClass.offset == 0)
281+ // {
282+ // // If the base class is at offset 0 that means it has yet to be adjusted.
283+ // // NOTE: This should only happen for `TIVSIClass`. If this assigns more than
284+ // // one base class to this offset we are screwed.
285+ // baseClass.offset = classOffset;
286+ // LogInfo("Adjusting base class offset for %llx to %llx", vftAddr, classOffset);
287+ // }
295288
296289 if (baseClass.offset == classOffset)
297290 {
@@ -345,6 +338,8 @@ std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI(uint64_t objectAddr)
345338 if (!subTypeInfoVariant.has_value ())
346339 {
347340 // Allow externals to be used in place of a backed subtype.
341+ // TODO: We should probably warn that vtables will likely be inaccurate.
342+ // TODO: Because we wont know what offsets are valid.
348343 auto externTypeName = nameFromTypeInfoSymbol (siClassTypeInfo.base_type );
349344 if (!externTypeName.has_value ())
350345 return std::nullopt ;
@@ -431,12 +426,17 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVFT(uint64_
431426 {
432427 // TODO: Sometimes vFunc idx will be zeroed iirc.
433428 // We allow vfuncs to point to extern functions.
434- if (!m_view->GetSymbolByAddress (vFuncAddr))
429+ auto vFuncSym = m_view->GetSymbolByAddress (vFuncAddr);
430+ if (!vFuncSym)
435431 break ;
436432 DataVariable dv;
437433 bool foundDv = m_view->GetDataVariableAtAddress (vFuncAddr, dv);
438434 // Last virtual function, or hit the next vtable.
439- if (!foundDv || dv.type .GetValue () == nullptr || !dv.type ->IsFunction ())
435+ if (!foundDv || !dv.type ->m_object )
436+ break ;
437+ // Void externs are very likely to be a func.
438+ // TODO: Add some sanity checks for this!
439+ if (!dv.type ->IsFunction () && !(dv.type ->IsVoid () && vFuncSym->GetType () == ExternalSymbol))
440440 break ;
441441 }
442442 else
@@ -488,6 +488,7 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVFT(uint64_
488488 // We should set the vtable as a base class so that xrefs are propagated (among other things).
489489 // NOTE: this means that `this` params will be assumed pre-adjusted, this is normally fine assuming type propagation
490490 // NOTE: never occurs on the vft types. Other-wise we need to change this.
491+ // TODO: Different type name please lol
491492 auto baseVftTypeName = fmt::format (" {}::VTable" , baseClassInfo->className );
492493 NamedTypeReferenceBuilder baseVftNTR;
493494 baseVftNTR.SetName (baseVftTypeName);
@@ -595,6 +596,7 @@ void ItaniumRTTIProcessor::ProcessRTTI()
595596 }
596597 };
597598
599+ m_view->BeginBulkModifySymbols ();
598600 // Scan data sections for rtti.
599601 for (const Ref<Section> §ion: m_view->GetSections ())
600602 {
@@ -604,6 +606,49 @@ void ItaniumRTTIProcessor::ProcessRTTI()
604606 scan (section);
605607 }
606608 }
609+ m_view->EndBulkModifySymbols ();
610+
611+ // Go through all classes and recurse into the base classes using the base class name
612+ for (auto &[classAddr, classInfo]: m_classInfo)
613+ {
614+ std::set<std::string> visitedBases;
615+ std::deque<BaseClassInfo> baseQueue (classInfo.baseClasses .begin (), classInfo.baseClasses .end ());
616+
617+ while (!baseQueue.empty ())
618+ {
619+ BaseClassInfo baseClass = baseQueue.front ();
620+ baseQueue.pop_front ();
621+
622+ if (visitedBases.find (baseClass.className ) != visitedBases.end ())
623+ continue ;
624+
625+ visitedBases.insert (baseClass.className );
626+
627+ auto baseClassIt = std::find_if (m_classInfo.begin (), m_classInfo.end (),
628+ [&](const auto &item) {
629+ return item.second .className == baseClass.className ;
630+ });
631+
632+ if (baseClassIt != m_classInfo.end ())
633+ {
634+ const ClassInfo &nestedBaseClassInfo = baseClassIt->second ;
635+ baseQueue.insert (baseQueue.end (), nestedBaseClassInfo.baseClasses .begin (),
636+ nestedBaseClassInfo.baseClasses .end ());
637+ }
638+
639+ classInfo.baseClasses .push_back (baseClass);
640+ }
641+
642+ // Remove duplicates in the baseClasses vector while preserving order
643+ std::sort (classInfo.baseClasses .begin (), classInfo.baseClasses .end (),
644+ [](const BaseClassInfo &a, const BaseClassInfo &b) { return a.className < b.className ; });
645+
646+ classInfo.baseClasses .erase (
647+ std::unique (classInfo.baseClasses .begin (), classInfo.baseClasses .end (),
648+ [](const BaseClassInfo &a, const BaseClassInfo &b) { return a.className == b.className ; }),
649+ classInfo.baseClasses .end ()
650+ );
651+ }
607652
608653 auto end_time = std::chrono::high_resolution_clock::now ();
609654 std::chrono::duration<double > elapsed_time = end_time - start_time;
@@ -613,6 +658,7 @@ void ItaniumRTTIProcessor::ProcessRTTI()
613658
614659void ItaniumRTTIProcessor::ProcessVFT ()
615660{
661+ BinaryReader optReader = BinaryReader (m_view);
616662 std::map<uint64_t , std::set<uint64_t >> vftMap = {};
617663 std::map<uint64_t , std::optional<VirtualFunctionTableInfo>> vftFinishedMap = {};
618664 auto start_time = std::chrono::high_resolution_clock::now ();
@@ -624,6 +670,11 @@ void ItaniumRTTIProcessor::ProcessVFT()
624670 DataVariable dv;
625671 if (m_view->GetDataVariableAtAddress (ref, dv) && m_classInfo.find (dv.address ) != m_classInfo.end ())
626672 continue ;
673+ // Verify that there is two 4 byte values above the type info pointer
674+ optReader.Seek (ref - 8 );
675+ auto beforeTypeInfoRef = optReader.ReadPointer ();
676+ if (m_view->IsValidOffset (beforeTypeInfoRef))
677+ continue ;
627678 // TODO: This is not pointing at where it should, remember that the vtable will be inside another structure.
628679 auto vftAddr = ref + m_view->GetAddressSize ();
629680 // Found a vtable reference to colocator
@@ -634,7 +685,6 @@ void ItaniumRTTIProcessor::ProcessVFT()
634685
635686 if (virtualFunctionTableSweep)
636687 {
637- BinaryReader optReader = BinaryReader (m_view);
638688 auto addrSize = m_view->GetAddressSize ();
639689 auto scan = [&](const Ref<Segment> &segment) {
640690 uint64_t startAddr = segment->GetStart ();
0 commit comments