summaryrefslogtreecommitdiff
path: root/plugins/rtti
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2025-03-19 23:19:49 -0400
committerMason Reed <mason@vector35.com>2025-03-19 23:19:49 -0400
commit1aa0bd3b0e15113c90f87744a1c3bae4ae79a283 (patch)
tree3a8324432d22f29aab53b392ab9fabe543ca62c6 /plugins/rtti
parent74e626f35f860f6a4590c1930180002b5924cf82 (diff)
Handle statically linked Itanium RTTI
I have a heavy dislike for this, but I also don't really have a better way of doing this without merging the VFT processing.
Diffstat (limited to 'plugins/rtti')
-rw-r--r--plugins/rtti/itanium.cpp46
1 files changed, 41 insertions, 5 deletions
diff --git a/plugins/rtti/itanium.cpp b/plugins/rtti/itanium.cpp
index 6ef47594..470f802d 100644
--- a/plugins/rtti/itanium.cpp
+++ b/plugins/rtti/itanium.cpp
@@ -227,6 +227,9 @@ Ref<Type> VMIClassTypeInfoType(BinaryView *view, uint64_t baseCount)
std::optional<TypeInfoVariant> ReadTypeInfoVariant(BinaryView *view, uint64_t objectAddr)
{
auto typeInfo = TypeInfo(view, objectAddr);
+
+ if (!view->IsValidOffset(typeInfo.base))
+ return std::nullopt;
// TODO: What if there is no symbol?
// 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
for (const auto& r : view->GetRelocationsAt(objectAddr))
if (auto relocSym = r->GetSymbol())
baseSym = relocSym;
- if (baseSym == nullptr)
- return std::nullopt;
}
- if (baseSym->GetType() != ExternalSymbol)
+
+ if (baseSym != nullptr && baseSym->GetType() != ExternalSymbol)
+ {
+ // The base did have a symbol, but it wasn't external.
+ // NOTE: We only require it to be external for symbol available bases.
return std::nullopt;
+ }
+
+ if (baseSym == nullptr)
+ {
+ // Verify first that we can even read a pointer sized value at the base.
+ if (!view->IsValidOffset(typeInfo.base + view->GetAddressSize()))
+ return std::nullopt;
+ // We did not find a symbol for the base.
+ // Last resort, try and deref to check for static linked c++ rt.
+ // to get the c++ variant assume we are in a vtable like this
+ // void* data_102bb4ca0 = _typeinfo_for___cxxabiv1::__class_type_info
+ // void *data_102bb4ca8 = __cxxabiv1::__class_type_info::~__class_type_info() <--- typeInfo.base points to this.
+ // void *data_102bb4cb0 = __cxxabiv1::__class_type_info::~__class_type_info()
+ // Because we are pointing at the start of the vtable, we can just deref again to get the symbol.
+ BinaryReader reader = BinaryReader(view);
+ reader.Seek(typeInfo.base);
+ uint64_t vftAddr = reader.ReadPointer();
+ if (!view->IsValidOffset(vftAddr))
+ return std::nullopt;
+ auto vftSym = view->GetSymbolByAddress(vftAddr);
+ if (vftSym == nullptr)
+ return std::nullopt;
+ baseSym = vftSym;
+ }
+
auto baseSymName = baseSym->GetShortName();
if (baseSymName.find("__cxxabiv1") != std::string::npos)
{
- // symbol takes the form of `abi::base_name`
+ // symbol takes the form of `abi::base_name::addend`
+ // Remove the `abi::`
auto baseTyStartPos = baseSymName.find("::");
if (baseTyStartPos != std::string::npos)
baseSymName = baseSymName.substr(baseTyStartPos + 2);
+ // Remove the `::addend`
+ auto baseTyEndPos = baseSymName.find("::");
+ if (baseTyEndPos != std::string::npos)
+ baseSymName = baseSymName.substr(0, baseTyEndPos);
if (baseSymName == "__class_type_info")
return TIVClass;
if (baseSymName == "__si_class_type_info")
return TIVSIClass;
if (baseSymName == "__vmi_class_type_info")
- return TIVVMIClass;
+ return TIVVMIClass;
}
return std::nullopt;
@@ -270,6 +305,7 @@ std::optional<BaseClassInfo> ItaniumRTTIProcessor::ProcessVFTBaseClassInfo(uint6
reader.Seek(vftAddr - 0x10);
auto adjustmentOffset = static_cast<int32_t>(reader.Read32());
+ [[maybe_unused]]
auto baseIdx = static_cast<int32_t>(reader.Read32());
uint64_t classOffset = std::abs(adjustmentOffset);