@@ -227,6 +227,9 @@ Ref<Type> VMIClassTypeInfoType(BinaryView *view, uint64_t baseCount)
227227std::optional<TypeInfoVariant> ReadTypeInfoVariant (BinaryView *view, uint64_t objectAddr)
228228{
229229 auto typeInfo = TypeInfo (view, objectAddr);
230+
231+ if (!view->IsValidOffset (typeInfo.base ))
232+ return std::nullopt ;
230233
231234 // TODO: What if there is no symbol?
232235 // If there is a symbol at objectAddr pointing to a symbol starting with "vtable for __cxxabiv1"
@@ -237,25 +240,57 @@ std::optional<TypeInfoVariant> ReadTypeInfoVariant(BinaryView *view, uint64_t ob
237240 for (const auto & r : view->GetRelocationsAt (objectAddr))
238241 if (auto relocSym = r->GetSymbol ())
239242 baseSym = relocSym;
240- if (baseSym == nullptr )
241- return std::nullopt ;
242243 }
243- if (baseSym->GetType () != ExternalSymbol)
244+
245+ if (baseSym != nullptr && baseSym->GetType () != ExternalSymbol)
246+ {
247+ // The base did have a symbol, but it wasn't external.
248+ // NOTE: We only require it to be external for symbol available bases.
244249 return std::nullopt ;
250+ }
251+
252+ if (baseSym == nullptr )
253+ {
254+ // Verify first that we can even read a pointer sized value at the base.
255+ if (!view->IsValidOffset (typeInfo.base + view->GetAddressSize ()))
256+ return std::nullopt ;
257+ // We did not find a symbol for the base.
258+ // Last resort, try and deref to check for static linked c++ rt.
259+ // to get the c++ variant assume we are in a vtable like this
260+ // void* data_102bb4ca0 = _typeinfo_for___cxxabiv1::__class_type_info
261+ // void *data_102bb4ca8 = __cxxabiv1::__class_type_info::~__class_type_info() <--- typeInfo.base points to this.
262+ // void *data_102bb4cb0 = __cxxabiv1::__class_type_info::~__class_type_info()
263+ // Because we are pointing at the start of the vtable, we can just deref again to get the symbol.
264+ BinaryReader reader = BinaryReader (view);
265+ reader.Seek (typeInfo.base );
266+ uint64_t vftAddr = reader.ReadPointer ();
267+ if (!view->IsValidOffset (vftAddr))
268+ return std::nullopt ;
269+ auto vftSym = view->GetSymbolByAddress (vftAddr);
270+ if (vftSym == nullptr )
271+ return std::nullopt ;
272+ baseSym = vftSym;
273+ }
274+
245275 auto baseSymName = baseSym->GetShortName ();
246276 if (baseSymName.find (" __cxxabiv1" ) != std::string::npos)
247277 {
248- // symbol takes the form of `abi::base_name`
278+ // symbol takes the form of `abi::base_name::addend`
279+ // Remove the `abi::`
249280 auto baseTyStartPos = baseSymName.find (" ::" );
250281 if (baseTyStartPos != std::string::npos)
251282 baseSymName = baseSymName.substr (baseTyStartPos + 2 );
283+ // Remove the `::addend`
284+ auto baseTyEndPos = baseSymName.find (" ::" );
285+ if (baseTyEndPos != std::string::npos)
286+ baseSymName = baseSymName.substr (0 , baseTyEndPos);
252287
253288 if (baseSymName == " __class_type_info" )
254289 return TIVClass;
255290 if (baseSymName == " __si_class_type_info" )
256291 return TIVSIClass;
257292 if (baseSymName == " __vmi_class_type_info" )
258- return TIVVMIClass;
293+ return TIVVMIClass;
259294 }
260295
261296 return std::nullopt ;
@@ -270,6 +305,7 @@ std::optional<BaseClassInfo> ItaniumRTTIProcessor::ProcessVFTBaseClassInfo(uint6
270305 reader.Seek (vftAddr - 0x10 );
271306
272307 auto adjustmentOffset = static_cast <int32_t >(reader.Read32 ());
308+ [[maybe_unused]]
273309 auto baseIdx = static_cast <int32_t >(reader.Read32 ());
274310 uint64_t classOffset = std::abs (adjustmentOffset);
275311
0 commit comments