1 //===-- ValueObjectVTable.cpp ---------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/ValueObject/ValueObjectVTable.h"
10 #include "lldb/Core/Module.h"
11 #include "lldb/Symbol/Function.h"
12 #include "lldb/Target/Language.h"
13 #include "lldb/Target/LanguageRuntime.h"
14 #include "lldb/ValueObject/ValueObjectChild.h"
15 #include "lldb/lldb-defines.h"
16 #include "lldb/lldb-enumerations.h"
17 #include "lldb/lldb-forward.h"
18 #include "lldb/lldb-private-enumerations.h"
21 using namespace lldb_private
;
23 class ValueObjectVTableChild
: public ValueObject
{
25 ValueObjectVTableChild(ValueObject
&parent
, uint32_t func_idx
,
27 : ValueObject(parent
), m_func_idx(func_idx
), m_addr_size(addr_size
) {
28 SetFormat(eFormatPointer
);
29 SetName(ConstString(llvm::formatv("[{0}]", func_idx
).str()));
32 ~ValueObjectVTableChild() override
= default;
34 std::optional
<uint64_t> GetByteSize() override
{ return m_addr_size
; };
36 llvm::Expected
<uint32_t> CalculateNumChildren(uint32_t max
) override
{
40 ValueType
GetValueType() const override
{ return eValueTypeVTableEntry
; };
42 bool IsInScope() override
{
43 if (ValueObject
*parent
= GetParent())
44 return parent
->IsInScope();
49 bool UpdateValue() override
{
50 SetValueIsValid(false);
52 ValueObject
*parent
= GetParent();
54 m_error
= Status::FromErrorString("owning vtable object not valid");
58 addr_t parent_addr
= parent
->GetValueAsUnsigned(LLDB_INVALID_ADDRESS
);
59 if (parent_addr
== LLDB_INVALID_ADDRESS
) {
60 m_error
= Status::FromErrorString("invalid vtable address");
64 ProcessSP process_sp
= GetProcessSP();
66 m_error
= Status::FromErrorString("no process");
70 TargetSP target_sp
= GetTargetSP();
72 m_error
= Status::FromErrorString("no target");
76 // Each `vtable_entry_addr` points to the function pointer.
77 addr_t vtable_entry_addr
= parent_addr
+ m_func_idx
* m_addr_size
;
79 process_sp
->ReadPointerFromMemory(vtable_entry_addr
, m_error
);
81 m_error
= Status::FromErrorStringWithFormat(
82 "failed to read virtual function entry 0x%16.16" PRIx64
,
87 // Set our value to be the load address of the function pointer in memory
88 // and our type to be the function pointer type.
89 m_value
.SetValueType(Value::ValueType::LoadAddress
);
90 m_value
.GetScalar() = vtable_entry_addr
;
92 // See if our resolved address points to a function in the debug info. If
93 // it does, then we can report the type as a function prototype for this
95 Function
*function
= nullptr;
96 Address resolved_vfunc_ptr_address
;
97 target_sp
->ResolveLoadAddress(vfunc_ptr
, resolved_vfunc_ptr_address
);
98 if (resolved_vfunc_ptr_address
.IsValid())
99 function
= resolved_vfunc_ptr_address
.CalculateSymbolContextFunction();
101 m_value
.SetCompilerType(function
->GetCompilerType().GetPointerType());
103 // Set our value's compiler type to a generic function protoype so that
104 // it displays as a hex function pointer for the value and the summary
105 // will display the address description.
107 // Get the original type that this vtable is based off of so we can get
108 // the language from it correctly.
109 ValueObject
*val
= parent
->GetParent();
110 auto type_system
= target_sp
->GetScratchTypeSystemForLanguage(
111 val
? val
->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus
);
113 m_value
.SetCompilerType(
114 (*type_system
)->CreateGenericFunctionPrototype().GetPointerType());
116 consumeError(type_system
.takeError());
120 // Now read our value into m_data so that our we can use the default
121 // summary provider for C++ for function pointers which will get the
122 // address description for our function pointer.
123 if (m_error
.Success()) {
124 const bool thread_and_frame_only_if_stopped
= true;
125 ExecutionContext
exe_ctx(
126 GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped
));
127 m_error
= m_value
.GetValueAsData(&exe_ctx
, m_data
, GetModule().get());
129 SetValueDidChange(true);
130 SetValueIsValid(true);
134 CompilerType
GetCompilerTypeImpl() override
{
135 return m_value
.GetCompilerType();
138 const uint32_t m_func_idx
;
139 const uint64_t m_addr_size
;
142 // For ValueObject only
143 ValueObjectVTableChild(const ValueObjectVTableChild
&) = delete;
144 const ValueObjectVTableChild
&
145 operator=(const ValueObjectVTableChild
&) = delete;
148 ValueObjectSP
ValueObjectVTable::Create(ValueObject
&parent
) {
149 return (new ValueObjectVTable(parent
))->GetSP();
152 ValueObjectVTable::ValueObjectVTable(ValueObject
&parent
)
153 : ValueObject(parent
) {
154 SetFormat(eFormatPointer
);
157 std::optional
<uint64_t> ValueObjectVTable::GetByteSize() {
159 return m_vtable_symbol
->GetByteSize();
163 llvm::Expected
<uint32_t> ValueObjectVTable::CalculateNumChildren(uint32_t max
) {
164 if (UpdateValueIfNeeded(false))
165 return m_num_vtable_entries
<= max
? m_num_vtable_entries
: max
;
169 ValueType
ValueObjectVTable::GetValueType() const { return eValueTypeVTable
; }
171 ConstString
ValueObjectVTable::GetTypeName() {
173 return m_vtable_symbol
->GetName();
174 return ConstString();
177 ConstString
ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); }
179 ConstString
ValueObjectVTable::GetDisplayTypeName() {
181 return m_vtable_symbol
->GetDisplayName();
182 return ConstString();
185 bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); }
187 ValueObject
*ValueObjectVTable::CreateChildAtIndex(size_t idx
) {
188 return new ValueObjectVTableChild(*this, idx
, m_addr_size
);
191 bool ValueObjectVTable::UpdateValue() {
193 m_flags
.m_children_count_valid
= false;
194 SetValueIsValid(false);
195 m_num_vtable_entries
= 0;
196 ValueObject
*parent
= GetParent();
198 m_error
= Status::FromErrorString("no parent object");
202 ProcessSP process_sp
= GetProcessSP();
204 m_error
= Status::FromErrorString("no process");
208 const LanguageType language
= parent
->GetObjectRuntimeLanguage();
209 LanguageRuntime
*language_runtime
= process_sp
->GetLanguageRuntime(language
);
211 if (language_runtime
== nullptr) {
212 m_error
= Status::FromErrorStringWithFormat(
213 "no language runtime support for the language \"%s\"",
214 Language::GetNameForLanguageType(language
));
218 // Get the vtable information from the language runtime.
219 llvm::Expected
<LanguageRuntime::VTableInfo
> vtable_info_or_err
=
220 language_runtime
->GetVTableInfo(*parent
, /*check_type=*/true);
221 if (!vtable_info_or_err
) {
222 m_error
= Status::FromError(vtable_info_or_err
.takeError());
226 TargetSP target_sp
= GetTargetSP();
227 const addr_t vtable_start_addr
=
228 vtable_info_or_err
->addr
.GetLoadAddress(target_sp
.get());
230 m_vtable_symbol
= vtable_info_or_err
->symbol
;
231 if (!m_vtable_symbol
) {
232 m_error
= Status::FromErrorStringWithFormat(
233 "no vtable symbol found containing 0x%" PRIx64
, vtable_start_addr
);
237 // Now that we know it's a vtable, we update the object's state.
238 SetName(GetTypeName());
240 // Calculate the number of entries
241 if (!m_vtable_symbol
->GetByteSizeIsValid()) {
242 m_error
= Status::FromErrorStringWithFormat(
243 "vtable symbol \"%s\" doesn't have a valid size",
244 m_vtable_symbol
->GetMangled().GetDemangledName().GetCString());
248 m_addr_size
= process_sp
->GetAddressByteSize();
249 const addr_t vtable_end_addr
=
250 m_vtable_symbol
->GetLoadAddress(target_sp
.get()) +
251 m_vtable_symbol
->GetByteSize();
252 m_num_vtable_entries
= (vtable_end_addr
- vtable_start_addr
) / m_addr_size
;
254 m_value
.SetValueType(Value::ValueType::LoadAddress
);
255 m_value
.GetScalar() = parent
->GetAddressOf();
256 auto type_system_or_err
=
257 target_sp
->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus
);
258 if (type_system_or_err
) {
259 m_value
.SetCompilerType(
260 (*type_system_or_err
)->GetBasicTypeFromAST(eBasicTypeUnsignedLong
));
262 consumeError(type_system_or_err
.takeError());
264 SetValueDidChange(true);
265 SetValueIsValid(true);
269 CompilerType
ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); }
271 ValueObjectVTable::~ValueObjectVTable() = default;