Skip to content

Commit 1aa0bd3

Browse files
committed
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.
1 parent 74e626f commit 1aa0bd3

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

plugins/rtti/itanium.cpp

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ Ref<Type> VMIClassTypeInfoType(BinaryView *view, uint64_t baseCount)
227227
std::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

Comments
 (0)