@@ -238,35 +238,6 @@ std::optional<TypeInfoVariant> ReadTypeInfoVariant(BinaryView *view, uint64_t ob
238238}
239239
240240
241- Ref<Metadata> ItaniumRTTIProcessor::SerializedMetadata ()
242- {
243- std::map<std::string, Ref<Metadata> > classesMeta;
244- for (auto &[coLocatorAddr, classInfo]: m_classInfo)
245- {
246- auto addrStr = std::to_string (coLocatorAddr);
247- classesMeta[addrStr] = classInfo.SerializedMetadata ();
248- }
249-
250- std::map<std::string, Ref<Metadata> > msvcMeta;
251- msvcMeta[" classes" ] = new Metadata (classesMeta);
252- return new Metadata (msvcMeta);
253- }
254-
255-
256- void ItaniumRTTIProcessor::DeserializedMetadata (const Ref<Metadata> &metadata)
257- {
258- std::map<std::string, Ref<Metadata> > msvcMeta = metadata->GetKeyValueStore ();
259- if (msvcMeta.find (" classes" ) != msvcMeta.end ())
260- {
261- for (auto &[objectAddrStr, classInfoMeta]: msvcMeta[" classes" ]->GetKeyValueStore ())
262- {
263- uint64_t objectAddr = std::stoull (objectAddrStr);
264- m_classInfo[objectAddr] = ClassInfo::DeserializedMetadata (classInfoMeta);
265- }
266- }
267- }
268-
269-
270241std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI (uint64_t objectAddr)
271242{
272243 // TODO: You cant get subobject offsets from rtti, its stored above this ptr in vtable.
@@ -279,7 +250,7 @@ std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI(uint64_t objectAddr)
279250 auto className = DemangleNameItanium (m_view, allowMangledClassNames, typeInfo.type_name );
280251 if (!className.has_value ())
281252 return std::nullopt ;
282- auto classInfo = ClassInfo{className.value ()};
253+ auto classInfo = ClassInfo{RTTIProcessorType::Itanium, className.value ()};
283254
284255 auto typeInfoName = fmt::format (" _typeinfo_for_{}" , classInfo.className );
285256 auto typeInfoSymbol = m_view->GetSymbolByAddress (objectAddr);
@@ -303,6 +274,8 @@ std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI(uint64_t objectAddr)
303274 return std::nullopt ;
304275 }
305276 classInfo.baseClassName = baseClassName;
277+ // NOTE: The base class offset is not able to be resolved here.
278+ // NOTE: To resolve the base class offset you must go to the vtable.
306279 m_view->DefineDataVariable (objectAddr, Confidence (SIClassTypeInfoType (m_view), 255 ));
307280 }
308281 else if (typeInfoVariant == TIVVMIClass)
@@ -321,12 +294,12 @@ std::optional<ClassInfo> ItaniumRTTIProcessor::ProcessRTTI(uint64_t objectAddr)
321294}
322295
323296
324- std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT (uint64_t vttAddr, const ClassInfo &classInfo)
297+ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVFT (uint64_t vftAddr, ClassInfo &classInfo)
325298{
326- VirtualFunctionTableInfo vttInfo = {vttAddr};
327- // Gather all virtual functions
299+ VirtualFunctionTableInfo vftInfo = {vftAddr};
328300 BinaryReader reader = BinaryReader (m_view);
329- reader.Seek (vttAddr);
301+ reader.Seek (vftAddr);
302+ // Gather all virtual functions
330303 std::vector<Ref<Function> > virtualFunctions = {};
331304 while (true )
332305 {
@@ -340,6 +313,7 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
340313 // Last CompleteObjectLocator or hit the next CompleteObjectLocator
341314 break ;
342315 }
316+ // TODO: Sometimes vFunc idx will be zeroed.
343317 // TODO: Is likely a function check here?
344318 m_logger->LogDebug (" Discovered function from virtual function table... %llx" , vFuncAddr);
345319 auto vFunc = m_view->AddFunctionForAnalysis (m_view->GetDefaultPlatform (), vFuncAddr, true );
@@ -351,19 +325,33 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
351325
352326 if (virtualFunctions.empty ())
353327 {
354- m_logger->LogDebug (" Skipping empty virtual function table... %llx" , vttAddr );
328+ m_logger->LogDebug (" Skipping empty virtual function table... %llx" , vftAddr );
355329 return std::nullopt ;
356330 }
357331
332+ // All vft verification has been done, we can write the classOffset now.
333+ if (classInfo.baseClassName .has_value () && !classInfo.classOffset .has_value ())
334+ {
335+ // Because we have this we _need_ to have the adjustment stuff.
336+ // NOTE: We assume two 0x4 ints with the first being what we want.
337+ // NOTE: This is where we actually classOffset is pulled.
338+ reader.Seek (vftAddr - 0x10 );
339+ auto adjustmentOffset = static_cast <int32_t >(reader.Read32 ());
340+ auto _what = static_cast <int32_t >(reader.Read32 ());
341+ uint64_t classOffset = std::abs (adjustmentOffset);
342+ classInfo.classOffset = classOffset;
343+ }
344+
345+
358346 for (auto &func: virtualFunctions)
359- vttInfo .virtualFunctions .emplace_back (VirtualFunctionInfo{func->GetStart ()});
347+ vftInfo .virtualFunctions .emplace_back (VirtualFunctionInfo{func->GetStart ()});
360348
361349 // Create virtual function table type
362350 auto vftTypeName = fmt::format (" {}::VTable" , classInfo.className );
363351 if (classInfo.baseClassName .has_value ())
364352 {
365- vftTypeName = fmt::format (" {}::{}" , classInfo.baseClassName .value (), vftTypeName);
366353 // TODO: What is the correct form for the name?
354+ vftTypeName = fmt::format (" {}::{}" , classInfo.baseClassName .value (), vftTypeName);
367355 }
368356 // TODO: Hack the debug type id is used here to allow the PDB type (debug info) to overwrite the RTTI vtable type.
369357 auto typeId = Type::GenerateAutoDebugTypeId (vftTypeName);
@@ -376,16 +364,16 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
376364 vftBuilder.SetPropagateDataVariableReferences (true );
377365 size_t vFuncIdx = 0 ;
378366
379- // Until https://github.com/Vector35/binaryninja-api/issues/5982 is fixed
367+ // TODO: Until https://github.com/Vector35/binaryninja-api/issues/5982 is fixed
380368 auto vftSize = virtualFunctions.size () * addrSize;
381369 vftBuilder.SetWidth (vftSize);
382370
383371 if (auto baseVft = classInfo.baseVft )
384372 {
385- if (classInfo. baseVft ->virtualFunctions .size () <= virtualFunctions.size ())
373+ if (baseVft->virtualFunctions .size () <= virtualFunctions.size ())
386374 {
387375 // Adjust the current vFunc index to the end of the shared vFuncs.
388- vFuncIdx = classInfo. baseVft ->virtualFunctions .size ();
376+ vFuncIdx = baseVft->virtualFunctions .size ();
389377 virtualFunctions.erase (virtualFunctions.begin (), virtualFunctions.begin () + vFuncIdx);
390378 // We should set the vtable as a base class so that xrefs are propagated (among other things).
391379 // NOTE: this means that `this` params will be assumed pre-adjusted, this is normally fine assuming type propagation
@@ -399,7 +387,7 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
399387 }
400388 else
401389 {
402- LogWarn (" Skipping adjustments for base VFT with more functions than sub VFT... %llx" , vttAddr );
390+ LogWarn (" Skipping adjustments for base VFT with more functions than sub VFT... %llx" , vftAddr );
403391 }
404392 }
405393
@@ -425,20 +413,22 @@ std::optional<VirtualFunctionTableInfo> ItaniumRTTIProcessor::ProcessVTT(uint64_
425413 Confidence (TypeBuilder::StructureType (vftBuilder.Finalize ()).Finalize (), RTTI_CONFIDENCE));
426414 }
427415
428- auto vftName = fmt::format (" _vtable_for_" , classInfo.className );
416+ auto vftName = fmt::format (" _vtable_for_{}" , classInfo.className );
417+ // TODO: How to display base classes?
429418 if (classInfo.baseClassName .has_value ())
430419 vftName += fmt::format (" {{for `{}'}}" , classInfo.baseClassName .value ());
431- auto vttSymbol = m_view->GetSymbolByAddress (vttAddr );
432- if (vttSymbol != nullptr )
433- m_view->UndefineAutoSymbol (vttSymbol );
434- m_view->DefineAutoSymbol (new Symbol{DataSymbol, vftName, vttAddr });
435- m_view->DefineDataVariable (vttAddr , Confidence (Type::NamedType (m_view, vftTypeName), RTTI_CONFIDENCE));
436- return vttInfo ;
420+ auto vftSymbol = m_view->GetSymbolByAddress (vftAddr );
421+ if (vftSymbol != nullptr )
422+ m_view->UndefineAutoSymbol (vftSymbol );
423+ m_view->DefineAutoSymbol (new Symbol{DataSymbol, vftName, vftAddr });
424+ m_view->DefineDataVariable (vftAddr , Confidence (Type::NamedType (m_view, vftTypeName), RTTI_CONFIDENCE));
425+ return vftInfo ;
437426}
438427
439428
440- ItaniumRTTIProcessor::ItaniumRTTIProcessor (const Ref<BinaryView> &view, bool useMangled, bool checkRData, bool vftSweep) : m_view(view)
429+ ItaniumRTTIProcessor::ItaniumRTTIProcessor (const Ref<BinaryView> &view, bool useMangled, bool checkRData, bool vftSweep)
441430{
431+ m_view = view;
442432 m_logger = new Logger (" Itanium RTTI" );
443433 allowMangledClassNames = useMangled;
444434 checkWritableRData = checkRData;
@@ -449,7 +439,7 @@ ItaniumRTTIProcessor::ItaniumRTTIProcessor(const Ref<BinaryView> &view, bool use
449439 if (metadata != nullptr )
450440 {
451441 // Load in metadata to the processor.
452- DeserializedMetadata (metadata);
442+ DeserializedMetadata (RTTIProcessorType::Itanium, metadata);
453443 }
454444}
455445
@@ -485,7 +475,7 @@ void ItaniumRTTIProcessor::ProcessRTTI()
485475}
486476
487477
488- void ItaniumRTTIProcessor::ProcessVTT ()
478+ void ItaniumRTTIProcessor::ProcessVFT ()
489479{
490480 std::map<uint64_t , uint64_t > vftMap = {};
491481 std::map<uint64_t , std::optional<VirtualFunctionTableInfo>> vftFinishedMap = {};
@@ -494,6 +484,10 @@ void ItaniumRTTIProcessor::ProcessVTT()
494484 {
495485 for (auto &ref: m_view->GetDataReferences (coLocatorAddr))
496486 {
487+ // Skip refs from other type info.
488+ DataVariable dv;
489+ if (m_view->GetDataVariableAtAddress (ref, dv) && m_classInfo.find (dv.address ) != m_classInfo.end ())
490+ continue ;
497491 // TODO: This is not pointing at where it should, remember that the vtable will be inside another structure.
498492 auto vftAddr = ref + m_view->GetAddressSize ();
499493 vftMap[coLocatorAddr] = vftAddr;
@@ -537,12 +531,12 @@ void ItaniumRTTIProcessor::ProcessVTT()
537531 }
538532 }
539533
540- auto GetCachedVFTInfo = [&](uint64_t vftAddr, const ClassInfo& classInfo) {
534+ auto GetCachedVFTInfo = [&](uint64_t vftAddr, ClassInfo& classInfo) {
541535 // Check in the cache so that we don't process vfts more than once.
542536 auto cachedVftInfo = vftFinishedMap.find (vftAddr);
543537 if (cachedVftInfo != vftFinishedMap.end ())
544538 return cachedVftInfo->second ;
545- auto vftInfo = ProcessVTT (vftAddr, classInfo);
539+ auto vftInfo = ProcessVFT (vftAddr, classInfo);
546540 vftFinishedMap[vftAddr] = vftInfo;
547541 return vftInfo;
548542 };
@@ -553,7 +547,7 @@ void ItaniumRTTIProcessor::ProcessVTT()
553547 if (classInfo.baseClassName .has_value ())
554548 {
555549 // Process base vtable and add it to the class info.
556- for (auto & [baseCoLocAddr, baseClassInfo] : m_classInfo)
550+ for (auto [baseCoLocAddr, baseClassInfo] : m_classInfo)
557551 {
558552 if (baseClassInfo.className == classInfo.baseClassName .value ())
559553 {
@@ -569,6 +563,8 @@ void ItaniumRTTIProcessor::ProcessVTT()
569563
570564 if (auto vftInfo = GetCachedVFTInfo (vftAddr, classInfo))
571565 classInfo.vft = vftInfo.value ();
566+
567+ m_classInfo[coLocatorAddr] = classInfo;
572568 }
573569
574570 auto end_time = std::chrono::high_resolution_clock::now ();
0 commit comments