@@ -452,6 +452,64 @@ std::optional<ClassInfo> MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA
452452
453453 auto ptrBaseTy = coLocator->signature ? RelativeToBinaryStartPointerBaseType : AbsolutePointerBaseType;
454454
455+ auto defineClassHierarchyDesc = [&](const uint64_t classHierarchyDescAddr, ClassInfo& classInfo, std::optional<CompleteObjectLocator> coLocator) {
456+ auto classHierarchyDesc = ClassHierarchyDescriptor (m_view, classHierarchyDescAddr);
457+ auto classHierarchyDescName = fmt::format (" {}::`RTTI Class Hierarchy Descriptor'" , classInfo.className );
458+ m_view->DefineAutoSymbol (new Symbol{DataSymbol, classHierarchyDescName, classHierarchyDescAddr});
459+ m_view->DefineDataVariable (classHierarchyDescAddr,
460+ Confidence (ClassHierarchyDescriptorType (m_view, ptrBaseTy), RTTI_CONFIDENCE));
461+
462+ auto baseClassArrayAddr = resolveAddr (classHierarchyDesc.pBaseClassArray );
463+ auto baseClassArray = BaseClassArray (m_view, baseClassArrayAddr, classHierarchyDesc.numBaseClasses );
464+ auto baseClassArrayName = fmt::format (" {}::`RTTI Base Class Array'" , classInfo.className );
465+ m_view->DefineAutoSymbol (new Symbol{DataSymbol, baseClassArrayName, baseClassArrayAddr});
466+ m_view->DefineDataVariable (baseClassArrayAddr,
467+ Confidence (BaseClassArrayType (m_view, baseClassArray.length , ptrBaseTy),
468+ RTTI_CONFIDENCE));
469+
470+ std::map<uint64_t , ClassInfo> baseClasses = {};
471+ for (auto pBaseClassDescAddr: baseClassArray.descriptors )
472+ {
473+ auto baseClassDescAddr = resolveAddr (pBaseClassDescAddr);
474+ auto baseClassDesc = BaseClassDescriptor (m_view, baseClassDescAddr);
475+
476+ auto baseClassTypeDescAddr = resolveAddr (baseClassDesc.pTypeDescriptor );
477+ auto baseClassTypeDesc = TypeDescriptor (m_view, baseClassTypeDescAddr);
478+ auto baseClassName = DemangleName (baseClassTypeDesc.name );
479+ if (!baseClassName.has_value ())
480+ {
481+ m_logger->LogWarn (" Skipping BaseClassDescriptor with mangled name %llx" , baseClassTypeDescAddr);
482+ continue ;
483+ }
484+
485+ // TODO: we probably want to maintain this state
486+ auto baseClassInfo = ClassInfo{baseClassName.value ()};
487+
488+ if (coLocator.has_value ())
489+ {
490+ if (baseClassDesc.where_mdisp == coLocator->offset && !classInfo.baseClassName .has_value () && classInfo.className != baseClassInfo.className )
491+ classInfo.baseClassName = baseClassInfo.className ;
492+ }
493+
494+ auto baseClassDescName = fmt::format (" {}::`RTTI Base Class Descriptor at ({},{},{},{})" , baseClassInfo.className ,
495+ baseClassDesc.where_mdisp , baseClassDesc.where_pdisp ,
496+ baseClassDesc.where_vdisp , baseClassDesc.attributes );
497+ m_view->DefineAutoSymbol (new Symbol{DataSymbol, baseClassDescName, baseClassDescAddr});
498+ m_view->DefineDataVariable (baseClassDescAddr,
499+ Confidence (BaseClassDescriptorType (m_view, ptrBaseTy), RTTI_CONFIDENCE));
500+
501+ auto baseClassTypeDescSymName = fmt::format (" class {} `RTTI Type Descriptor'" , baseClassInfo.className );
502+ m_view->DefineAutoSymbol (new Symbol{DataSymbol, baseClassTypeDescSymName, baseClassTypeDescAddr});
503+ m_view->DefineDataVariable (baseClassTypeDescAddr,
504+ Confidence (TypeDescriptorType (m_view, baseClassTypeDesc.name .length ()), RTTI_CONFIDENCE));
505+
506+ auto classHierarchyDescAddr = resolveAddr (baseClassDesc.pClassHierarchyDescriptor );
507+ baseClasses[classHierarchyDescAddr] = baseClassInfo;
508+ }
509+
510+ return baseClasses;
511+ };
512+
455513 // Get type descriptor then check to see if the class name was demangled.
456514 auto typeDescAddr = resolveAddr (coLocator->pTypeDescriptor );
457515 auto typeDesc = TypeDescriptor (m_view, typeDescAddr);
@@ -480,43 +538,21 @@ std::optional<ClassInfo> MicrosoftRTTIProcessor::ProcessRTTI(uint64_t coLocatorA
480538 Confidence (TypeDescriptorType (m_view, typeDesc.name .length ()), RTTI_CONFIDENCE));
481539
482540 auto classHierarchyDescAddr = resolveAddr (coLocator->pClassHierarchyDescriptor );
483- auto classHierarchyDesc = ClassHierarchyDescriptor (m_view, classHierarchyDescAddr);
484- auto classHierarchyDescName = fmt::format (" {}::`RTTI Class Hierarchy Descriptor'" , classInfo.className );
485- m_view->DefineAutoSymbol (new Symbol{DataSymbol, classHierarchyDescName, classHierarchyDescAddr});
486- m_view->DefineDataVariable (classHierarchyDescAddr,
487- Confidence (ClassHierarchyDescriptorType (m_view, ptrBaseTy), RTTI_CONFIDENCE));
488-
489- auto baseClassArrayAddr = resolveAddr (classHierarchyDesc.pBaseClassArray );
490- auto baseClassArray = BaseClassArray (m_view, baseClassArrayAddr, classHierarchyDesc.numBaseClasses );
491- auto baseClassArrayName = fmt::format (" {}::`RTTI Base Class Array'" , classInfo.className );
492- m_view->DefineAutoSymbol (new Symbol{DataSymbol, baseClassArrayName, baseClassArrayAddr});
493- m_view->DefineDataVariable (baseClassArrayAddr,
494- Confidence (BaseClassArrayType (m_view, baseClassArray.length , ptrBaseTy),
495- RTTI_CONFIDENCE));
496-
497- for (auto pBaseClassDescAddr: baseClassArray.descriptors )
541+ auto baseClasses = defineClassHierarchyDesc (classHierarchyDescAddr, classInfo, coLocator);
542+ m_visitedClassHierarchyDescAddrs.insert (classHierarchyDescAddr);
543+ while (baseClasses.size () > 0 )
498544 {
499- auto baseClassDescAddr = resolveAddr (pBaseClassDescAddr);
500- auto baseClassDesc = BaseClassDescriptor (m_view, baseClassDescAddr);
501-
502- auto baseClassTypeDescAddr = resolveAddr (baseClassDesc.pTypeDescriptor );
503- auto baseClassTypeDesc = TypeDescriptor (m_view, baseClassTypeDescAddr);
504- auto baseClassName = DemangleName (baseClassTypeDesc.name );
505- if (!baseClassName.has_value ())
545+ std::map<uint64_t , ClassInfo> newBaseClasses = {};
546+ for (auto & [baseClassHierarchyDescAddr, baseClassInfo] : baseClasses)
506547 {
507- m_logger->LogWarn (" Skipping BaseClassDescriptor with mangled name %llx" , baseClassTypeDescAddr);
508- continue ;
509- }
548+ if (m_visitedClassHierarchyDescAddrs.find (baseClassHierarchyDescAddr) != m_visitedClassHierarchyDescAddrs.end ())
549+ continue ;
510550
511- if (baseClassDesc.where_mdisp == coLocator->offset && classInfo.className != baseClassName.value ())
512- classInfo.baseClassName = baseClassName;
551+ newBaseClasses.merge (defineClassHierarchyDesc (baseClassHierarchyDescAddr, baseClassInfo, std::nullopt ));
552+ m_visitedClassHierarchyDescAddrs.insert (baseClassHierarchyDescAddr);
553+ }
513554
514- auto baseClassDescName = fmt::format (" {}::`RTTI Base Class Descriptor at ({},{},{},{})" , baseClassName.value (),
515- baseClassDesc.where_mdisp , baseClassDesc.where_pdisp ,
516- baseClassDesc.where_vdisp , baseClassDesc.attributes );
517- m_view->DefineAutoSymbol (new Symbol{DataSymbol, baseClassDescName, baseClassDescAddr});
518- m_view->DefineDataVariable (baseClassDescAddr,
519- Confidence (BaseClassDescriptorType (m_view, ptrBaseTy), RTTI_CONFIDENCE));
555+ baseClasses = newBaseClasses;
520556 }
521557
522558 auto coLocatorName = fmt::format (" {}::`RTTI Complete Object Locator'" , className.value ());
@@ -661,6 +697,7 @@ MicrosoftRTTIProcessor::MicrosoftRTTIProcessor(const Ref<BinaryView> &view, bool
661697 allowAnonymousClassNames = allowAnonymous;
662698 checkWritableRData = checkRData;
663699 m_classInfo = {};
700+ m_visitedClassHierarchyDescAddrs = {};
664701 virtualFunctionTableSweep = vftSweep;
665702 auto metadata = view->QueryMetadata (VIEW_METADATA_MSVC);
666703 if (metadata != nullptr )
0 commit comments