[Lldb-commits] [lldb] Add the ability to get a C++ vtable ValueObject from another ValueObj… (PR #67599)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 27 13:10:28 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
<details>
<summary>Changes</summary>
Add the ability to get a C++ vtable ValueObject from another ValueObject.
This patch adds the ability to ask a ValueObject for a ValueObject that represents the virtual function table for a C++ class. If the ValueObject is not a C++ class with a vtable, a valid ValueObject value will be returned that contains an appropriate error. If it is successful a valid ValueObject that represents vtable will be returned. The ValueObject that is returned will have a name that matches the demangled value for a C++ vtable mangled name like "vtable for <class-name>". It will have N children, one for each virtual function pointer. Each child's value is the function pointer itself, the summary is the symbolication of this function pointer, and the type will be a valid function pointer from the debug info if there is debug information corresponding to the virtual function pointer.
The vtable SBValue will have the following:
- SBValue::GetName() returns "vtable for <class>"
- SBValue::GetValue() returns a string representation of the vtable address
- SBValue::GetSummary() returns NULL
- SBValue::GetType() returns a type appropriate for a uintptr_t type for the current process
- SBValue::GetLoadAddress() returns the address of the vtable adderess
- SBValue::GetValueAsUnsigned(...) returns the vtable address
- SBValue::GetNumChildren() returns the number of virtual function pointers in the vtable
- SBValue::GetChildAtIndex(...) returns a SBValue that represents a virtual function pointer
The child SBValue objects that represent a virtual function pointer has the following values:
- SBValue::GetName() returns "[%u]" where %u is the vtable function pointer index
- SBValue::GetValue() returns a string representation of the virtual function pointer
- SBValue::GetSummary() returns a symbolicated respresentation of the virtual function pointer
- SBValue::GetType() returns the function prototype type if there is debug info, or a generic funtion prototype if there is no debug info
- SBValue::GetLoadAddress() returns the address of the virtual function pointer
- SBValue::GetValueAsUnsigned(...) returns the virtual function pointer
- SBValue::GetNumChildren() returns 0
- SBValue::GetChildAtIndex(...) returns invalid SBValue for any index
Examples of using this API via python:
```
(lldb) script vtable = lldb.frame.FindVariable("shape_ptr").GetVTable()
(lldb) script vtable
vtable for Shape = 0x0000000100004088 {
[0] = 0x0000000100003d20 a.out`Shape::~Shape() at main.cpp:3
[1] = 0x0000000100003e4c a.out`Shape::~Shape() at main.cpp:3
[2] = 0x0000000100003e7c a.out`Shape::area() at main.cpp:4
[3] = 0x0000000100003e3c a.out`Shape::optional() at main.cpp:7
}
(lldb) script c = vtable.GetChildAtIndex(0)
(lldb) script c
(void ()) [0] = 0x0000000100003d20 a.out`Shape::~Shape() at main.cpp:3
```
---
Patch is 33.01 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/67599.diff
18 Files Affected:
- (modified) lldb/include/lldb/API/SBValue.h (+28)
- (modified) lldb/include/lldb/Core/ValueObject.h (+4)
- (modified) lldb/include/lldb/Core/ValueObjectChild.h (+1)
- (added) lldb/include/lldb/Core/ValueObjectVTable.h (+65)
- (modified) lldb/include/lldb/Symbol/TypeSystem.h (+4)
- (modified) lldb/include/lldb/lldb-enumerations.h (+3-1)
- (modified) lldb/source/API/SBValue.cpp (+14-3)
- (modified) lldb/source/Commands/CommandObjectFrame.cpp (+2)
- (modified) lldb/source/Core/CMakeLists.txt (+1)
- (modified) lldb/source/Core/ValueObject.cpp (+5)
- (added) lldb/source/Core/ValueObjectVTable.cpp (+325)
- (modified) lldb/source/DataFormatters/CXXFunctionPointer.cpp (+5-1)
- (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+3-1)
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+25-1)
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+4)
- (added) lldb/test/API/functionalities/vtable/Makefile (+3)
- (added) lldb/test/API/functionalities/vtable/TestVTableValue.py (+135)
- (added) lldb/test/API/functionalities/vtable/main.cpp (+37)
``````````diff
diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h
index b66c2d5642b6f95..333bdf1738eecaf 100644
--- a/lldb/include/lldb/API/SBValue.h
+++ b/lldb/include/lldb/API/SBValue.h
@@ -374,6 +374,34 @@ class LLDB_API SBValue {
lldb::SBWatchpoint WatchPointee(bool resolve_location, bool read, bool write,
SBError &error);
+ /// If this value represents a C++ class that has a vtable, return an value
+ /// that represents the virtual function table.
+ ///
+ /// SBValue::GetError() will be in the success state if this value represents
+ /// a C++ class with a vtable, or an appropriate error describing that the
+ /// object isn't a C++ class with a vtable or not a C++ class.
+ ///
+ /// SBValue::GetName() will be the demangled symbol name for the virtual
+ /// function table like "vtable for Baseclass".
+ ///
+ /// SBValue::GetValue() will be the address of the first vtable entry if the
+ /// current SBValue is a class with a vtable, or nothing the current SBValue
+ /// is not a C++ class or not a C++ class that has a vtable.
+ ///
+ /// SBValue::GetSummary() will contain the number of virtual function pointers
+ /// in the vtable like is done for arrays.
+ ///
+ /// SBValue::GetNumChildren() will return the number of virtual function
+ /// pointers in the vtable, or zero on error.
+ ///
+ /// SBValue::GetChildAtIndex(...) will return each virtual function pointer
+ /// as a SBValue object. The child SBValue objects name will be the array
+ /// index, value will be the virtual function pointer, summary will be the
+ /// symbolicated address description, and if the the adress resolves to a
+ /// function in debug info, the child type will be the function prototype as
+ /// a SBType object.
+ lldb::SBValue GetVTable();
+
protected:
friend class SBBlock;
friend class SBFrame;
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 3af94f0a86e2fcc..20b3086138457f7 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -620,6 +620,10 @@ class ValueObject {
virtual lldb::ValueObjectSP CastPointerType(const char *name,
lldb::TypeSP &type_sp);
+ /// If this object represents a C++ class with a vtable, return an object
+ /// that represents the virtual function table. If the object isn't a class
+ /// with a vtable, return a valid ValueObject with the error set correctly.
+ lldb::ValueObjectSP GetVTable();
// The backing bits of this value object were updated, clear any descriptive
// string, so we know we have to refetch them.
void ValueUpdated() {
diff --git a/lldb/include/lldb/Core/ValueObjectChild.h b/lldb/include/lldb/Core/ValueObjectChild.h
index 07b37aa8a405f7e..46b14e6840f0dc3 100644
--- a/lldb/include/lldb/Core/ValueObjectChild.h
+++ b/lldb/include/lldb/Core/ValueObjectChild.h
@@ -73,6 +73,7 @@ class ValueObjectChild : public ValueObject {
friend class ValueObject;
friend class ValueObjectConstResult;
friend class ValueObjectConstResultImpl;
+ friend class ValueObjectVTable;
ValueObjectChild(ValueObject &parent, const CompilerType &compiler_type,
ConstString name, uint64_t byte_size,
diff --git a/lldb/include/lldb/Core/ValueObjectVTable.h b/lldb/include/lldb/Core/ValueObjectVTable.h
new file mode 100644
index 000000000000000..faa0af238e764f4
--- /dev/null
+++ b/lldb/include/lldb/Core/ValueObjectVTable.h
@@ -0,0 +1,65 @@
+//===-- ValueObjectVTable.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_CORE_VALUEOBJECTVTABLE_H
+#define LLDB_CORE_VALUEOBJECTVTABLE_H
+
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+/// A class that represents a virtual function table for a C++ class.
+///
+///
+class ValueObjectVTable : public ValueObject {
+public:
+ ~ValueObjectVTable() override;
+
+ static lldb::ValueObjectSP Create(ValueObject &parent);
+
+ std::optional<uint64_t> GetByteSize() override;
+
+ size_t CalculateNumChildren(uint32_t max) override;
+
+ ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member,
+ int32_t synthetic_index) override;
+
+ lldb::ValueType GetValueType() const override;
+
+ ConstString GetTypeName() override;
+
+ ConstString GetQualifiedTypeName() override;
+
+ ConstString GetDisplayTypeName() override;
+
+ bool IsInScope() override;
+
+protected:
+ bool UpdateValue() override;
+
+ CompilerType GetCompilerTypeImpl() override;
+
+ /// The symbol for the C++ virtual function table.
+ Symbol *m_vtable_symbol = nullptr;
+ /// Cache the number of vtable children when we update the value.
+ uint32_t m_num_vtable_entries = 0;
+ /// Cache the address size in bytes to avoid checking with the process to
+ /// many times.
+ uint32_t m_addr_size = 0;
+
+private:
+ ValueObjectVTable(ValueObject &parent);
+
+ // For ValueObject only
+ ValueObjectVTable(const ValueObjectVTable &) = delete;
+ const ValueObjectVTable &operator=(const ValueObjectVTable &) = delete;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_CORE_VALUEOBJECTVTABLE_H
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index eb6e453e1aec0d0..16b912c8113f969 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -444,6 +444,10 @@ class TypeSystem : public PluginInterface,
virtual CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) = 0;
+ virtual CompilerType CreateGenericFunctionPrototype() {
+ return CompilerType();
+ }
+
virtual CompilerType
GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding,
size_t bit_size) = 0;
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 21e098481ce8022..b9dae9ca5573d5b 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -322,7 +322,9 @@ enum ValueType {
eValueTypeRegister = 5, ///< stack frame register value
eValueTypeRegisterSet = 6, ///< A collection of stack frame register values
eValueTypeConstResult = 7, ///< constant result variables
- eValueTypeVariableThreadLocal = 8 ///< thread local storage variable
+ eValueTypeVariableThreadLocal = 8, ///< thread local storage variable
+ eValueTypeVTable = 9, ///< virtual function table
+ eValueTypeVTableEntry = 10, ///< function pointer in virtual function table
};
/// Token size/granularities for Input Readers.
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index 738773c93c49b03..cf2d862fa504844 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -114,7 +114,7 @@ class ValueImpl {
Target *target = value_sp->GetTargetSP().get();
// If this ValueObject holds an error, then it is valuable for that.
- if (value_sp->GetError().Fail())
+ if (value_sp->GetError().Fail())
return value_sp;
if (!target)
@@ -1038,8 +1038,8 @@ lldb::ValueObjectSP SBValue::GetSP(ValueLocker &locker) const {
// IsValid means that the SBValue has a value in it. But that's not the
// only time that ValueObjects are useful. We also want to return the value
// if there's an error state in it.
- if (!m_opaque_sp || (!m_opaque_sp->IsValid()
- && (m_opaque_sp->GetRootSP()
+ if (!m_opaque_sp || (!m_opaque_sp->IsValid()
+ && (m_opaque_sp->GetRootSP()
&& !m_opaque_sp->GetRootSP()->GetError().Fail()))) {
locker.GetError().SetErrorString("No value");
return ValueObjectSP();
@@ -1498,3 +1498,14 @@ lldb::SBValue SBValue::Persist() {
}
return persisted_sb;
}
+
+lldb::SBValue SBValue::GetVTable() {
+ SBValue vtable_sb;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (!value_sp)
+ return vtable_sb;
+
+ vtable_sb.SetSP(value_sp->GetVTable());
+ return vtable_sb;
+}
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 1390fd8748dfaf6..2149d0f2f98da3d 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -495,6 +495,8 @@ may even involve JITing and running code in the target program.)");
case eValueTypeRegisterSet:
case eValueTypeConstResult:
case eValueTypeVariableThreadLocal:
+ case eValueTypeVTable:
+ case eValueTypeVTableEntry:
return false;
}
}
diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt
index d7b4f2587a98bf9..b23cc5d2eaf3156 100644
--- a/lldb/source/Core/CMakeLists.txt
+++ b/lldb/source/Core/CMakeLists.txt
@@ -71,6 +71,7 @@ add_lldb_library(lldbCore
ValueObjectSyntheticFilter.cpp
ValueObjectUpdater.cpp
ValueObjectVariable.cpp
+ ValueObjectVTable.cpp
DEPENDS
clang-tablegen-targets
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 3e9116f2d922933..aa2a35bf2b2dc5f 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -17,6 +17,7 @@
#include "lldb/Core/ValueObjectDynamicValue.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Core/ValueObjectSyntheticFilter.h"
+#include "lldb/Core/ValueObjectVTable.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
#include "lldb/DataFormatters/FormatManager.h"
@@ -3155,3 +3156,7 @@ ValueObjectSP ValueObject::Persist() {
return persistent_var_sp->GetValueObject();
}
+
+lldb::ValueObjectSP ValueObject::GetVTable() {
+ return ValueObjectVTable::Create(*this);
+}
diff --git a/lldb/source/Core/ValueObjectVTable.cpp b/lldb/source/Core/ValueObjectVTable.cpp
new file mode 100644
index 000000000000000..31c619986b825f1
--- /dev/null
+++ b/lldb/source/Core/ValueObjectVTable.cpp
@@ -0,0 +1,325 @@
+//===-- ValueObjectVTable.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/ValueObjectVTable.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueObjectVTableChild : public ValueObject {
+public:
+ ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
+ uint64_t addr_size)
+ : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
+ SetFormat(eFormatPointer);
+ SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
+ }
+
+ ~ValueObjectVTableChild() override = default;
+
+ std::optional<uint64_t> GetByteSize() override { return m_addr_size; };
+
+ size_t CalculateNumChildren(uint32_t max) override { return 0; };
+
+ ValueType GetValueType() const override { return eValueTypeVTableEntry; };
+
+ bool IsInScope() override {
+ ValueObject *parent = GetParent();
+ if (parent)
+ return parent->IsInScope();
+ return false;
+ };
+
+protected:
+ bool UpdateValue() override {
+ SetValueIsValid(false);
+ m_value.Clear();
+ ValueObject *parent = GetParent();
+ if (!parent) {
+ m_error.SetErrorString("no parent object");
+ return false;
+ }
+
+ addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (parent_addr == LLDB_INVALID_ADDRESS) {
+ m_error.SetErrorString("parent has invalid address");
+ return false;
+ }
+
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp) {
+ m_error.SetErrorString("no process");
+ return false;
+ }
+
+ TargetSP target_sp = GetTargetSP();
+ if (!target_sp) {
+ m_error.SetErrorString("no target");
+ return false;
+ }
+
+ // Each `vtable_entry_addr` points to the function pointer.
+ addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
+ addr_t vfunc_ptr =
+ process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
+ if (m_error.Fail()) {
+ m_error.SetErrorStringWithFormat(
+ "failed to read virtual function entry 0x%16.16" PRIx64,
+ vtable_entry_addr);
+ return false;
+ }
+
+ Address resolved_vfunc_ptr_address;
+ target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
+ if (!resolved_vfunc_ptr_address.IsValid()) {
+ m_error.SetErrorStringWithFormat(
+ "unable to resolve func ptr address: 0x%16.16" PRIx64, vfunc_ptr);
+ return false;
+ }
+
+ // Set our value to be the load address of the function pointer in memory
+ // and our type to be the function pointer type.
+ m_value.SetValueType(Value::ValueType::LoadAddress);
+ m_value.GetScalar() = vtable_entry_addr;
+
+ // See if our resolved address points to a function in the debug info. If
+ // it does, then we can report the type as a function prototype for this
+ // function.
+ Function *function =
+ resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
+ if (function) {
+ m_value.SetCompilerType(function->GetCompilerType());
+ } else {
+ // Set our value's compiler type to a generic function protoype so that
+ // it displays as a hex function pointer for the value and the summary
+ // will display the address description.
+ auto type_system_or_err =
+ target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+ if (type_system_or_err) {
+ CompilerType proto = (*type_system_or_err)->CreateGenericFunctionPrototype();
+ if (proto.IsFunctionType())
+ m_value.SetCompilerType(proto);
+ } else {
+ consumeError(type_system_or_err.takeError());
+ }
+ }
+
+ // Now read our value into m_data so that our we can use the default
+ // summary provider for C++ for function pointers which will get the
+ // address description for our function pointer.
+ if (m_error.Success()) {
+ const bool thread_and_frame_only_if_stopped = true;
+ ExecutionContext exe_ctx(
+ GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
+ m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
+ }
+ SetValueDidChange(true);
+ SetValueIsValid(true);
+ return true;
+ };
+
+ CompilerType GetCompilerTypeImpl() override {
+ return m_value.GetCompilerType();
+ };
+
+ const uint32_t m_func_idx;
+ const uint64_t m_addr_size;
+
+private:
+ // For ValueObject only
+ ValueObjectVTableChild(const ValueObjectVTableChild &) = delete;
+ const ValueObjectVTableChild &
+ operator=(const ValueObjectVTableChild &) = delete;
+};
+
+ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) {
+ return (new ValueObjectVTable(parent))->GetSP();
+}
+
+ValueObjectVTable::ValueObjectVTable(ValueObject &parent)
+ : ValueObject(parent) {
+ SetFormat(eFormatPointer);
+}
+
+std::optional<uint64_t> ValueObjectVTable::GetByteSize() {
+ if (m_vtable_symbol)
+ return m_vtable_symbol->GetByteSize();
+ else
+ return std::nullopt;
+}
+
+size_t ValueObjectVTable::CalculateNumChildren(uint32_t max) {
+ if (UpdateValueIfNeeded(false))
+ return m_num_vtable_entries <= max ? m_num_vtable_entries : max;
+ return 0;
+}
+
+ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; }
+
+ConstString ValueObjectVTable::GetTypeName() {
+ if (m_vtable_symbol)
+ return m_vtable_symbol->GetName();
+ return ConstString();
+}
+
+ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); }
+
+ConstString ValueObjectVTable::GetDisplayTypeName() {
+ if (m_vtable_symbol)
+ return m_vtable_symbol->GetDisplayName();
+ return ConstString();
+}
+
+bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); }
+
+ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx,
+ bool synthetic_array_member,
+ int32_t synthetic_index) {
+ if (synthetic_array_member)
+ return nullptr;
+ return new ValueObjectVTableChild(*this, idx, m_addr_size);
+}
+
+bool ValueObjectVTable::UpdateValue() {
+ m_error.Clear();
+ m_flags.m_children_count_valid = false;
+ SetValueIsValid(false);
+ m_num_vtable_entries = 0;
+ ValueObject *parent = GetParent();
+ if (!parent) {
+ m_error.SetErrorString("no parent object");
+ return false;
+ }
+
+ // Check to make sure the class has a vtable.
+
+ // If we have a pointer or reference type, get the pointee type from this
+ // so we can ask if it has virtual functions below.
+ CompilerType value_type = parent->GetCompilerType();
+ if (value_type.IsPointerOrReferenceType()) {
+ CompilerType pointee_type = value_type.GetPointeeType();
+ if (pointee_type)
+ value_type = pointee_type;
+ }
+
+ // Make sure this is a class or a struct first by checking the type class
+ // bitfield that gets returned.
+ if ((value_type.GetTypeClass() & (eTypeClassStruct | eTypeClassClass)) == 0) {
+ m_error.SetErrorStringWithFormat("type \"%s\" is not a class or struct",
+ value_type.GetTypeName().AsCString("<invalid>"));
+ return false;
+ }
+
+ // Check if the type has virtual functions by asking it if it is polymorphic.
+ if (!value_type.IsPolymorphicClass()) {
+ m_error.SetErrorStringWithFormat("type \"%s\" doesn't have a vtable",
+ value_type.GetTypeName().AsCString("<invalid>"));
+ return false;
+ }
+
+ TargetSP target_sp = GetTargetSP();
+ if (!target_sp) {
+ m_error.SetErrorString("no target");
+ return false;
+ }
+
+ // Get the address of our parent. This will update the parent value object
+ // if needed and fetch the address of the parent.
+ AddressType addr_type;
+ addr_t parent_load_addr =
+ parent->GetAddressOf(/*scalar_is_load_address=*/true, &addr_type);
+ if (addr_type == eAddressTypeFile) {
+ ModuleSP module_sp(parent->GetModule());
+ if (!module_sp) {
+ parent_load_addr = LLDB_INVALID_ADDRESS;
+ } else {
+ Address addr;
+ module_sp->ResolveFileAddress(parent_load_addr, addr);
+ parent_load_addr = addr.GetLoadAddress(target_sp.get());
+ }
+ } else if (addr_type == eAddressTypeHost ||
+ addr_type == eAddressTypeInvalid) {
+ parent_load_addr = LLDB_INVALID_ADDRESS;
+ }
+
+ if (parent_load_addr == LLDB_INVALID_ADDRESS) {
+ m_error.SetErrorString("parent is not in memory");
+ return false;
+ }
+
+ m_value.Clear();
+
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp) {
+ m_error.SetErrorString("no process");
+ return false;
+ }
+
+ // We expect to find the vtable at the first block of memory.
+ addr_t possible_vtable_ptr =
+ process_sp->ReadPointerFromMemory(parent_load_addr, m_error);
+ if (m_error.Fail())
+ return false;
+
+ Address resolved_possible_vtable_address;
+ target_sp->ResolveLoadAddress(possible_vtable_ptr,
+ resolved_possible_vtable_address);
+ if (!resolved_possible_vtable_address.IsValid()) {
+ m_error.SetErrorStringWithFormat(
+ "unable to resolve 0x%" PRIx64 " to a section for vtable "
+ "symbol search", possible_vtable_ptr);
+ return false;
+ }
+
+ m_vtable_symbol =
+ resolved_possible_vtable_address.CalculateSymbolContextSymbol();
+ if (!(m_vtable_symbol &&
+ m_vtable_symbol->GetName().GetStringRef().startswith("vtable for "))) {
+ m_error.SetErrorStringWithFormat(
+ "no vtable symbol found containing 0x%" PRIx64, possible_vtable_ptr);
+ return false;
+ }
+
+ // Now that we know it's a vta...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/67599
More information about the lldb-commits
mailing list