LLDB mainline
ValueObjectVTable.cpp
Go to the documentation of this file.
1//===-- ValueObjectVTable.cpp ---------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
10#include "lldb/Core/Module.h"
15#include "lldb/lldb-defines.h"
17#include "lldb/lldb-forward.h"
19
20#include "llvm/Support/Error.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
26public:
27 ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
28 uint64_t addr_size)
29 : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
31 SetName(llvm::formatv("[{0}]", func_idx).str());
32 }
33
34 ~ValueObjectVTableChild() override = default;
35
36 llvm::Expected<uint64_t> GetByteSize() override { return m_addr_size; };
37
38 llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override {
39 return 0;
40 };
41
42 ValueType GetValueType() const override { return eValueTypeVTableEntry; };
43
44 bool IsInScope() override {
45 if (ValueObject *parent = GetParent())
46 return parent->IsInScope();
47 return false;
48 };
49
50protected:
51 bool UpdateValue() override {
52 SetValueIsValid(false);
53 m_value.Clear();
54 ValueObject *parent = GetParent();
55 if (!parent) {
56 m_error = Status::FromErrorString("owning vtable object not valid");
57 return false;
58 }
59
60 addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
61 if (parent_addr == LLDB_INVALID_ADDRESS) {
62 m_error = Status::FromErrorString("invalid vtable address");
63 return false;
64 }
65
66 ProcessSP process_sp = GetProcessSP();
67 if (!process_sp) {
68 m_error = Status::FromErrorString("no process");
69 return false;
70 }
71
72 TargetSP target_sp = GetTargetSP();
73 if (!target_sp) {
74 m_error = Status::FromErrorString("no target");
75 return false;
76 }
77
78 parent_addr = process_sp->FixCodeAddress(parent_addr);
79
80 // Each `vtable_entry_addr` points to the function pointer.
81 addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
82 llvm::Expected<lldb::addr_t> vfunc_ptr_or_err =
83 process_sp->ReadPointerFromMemory(vtable_entry_addr);
84 if (!vfunc_ptr_or_err) {
85 llvm::consumeError(vfunc_ptr_or_err.takeError());
87 "failed to read virtual function entry 0x%16.16" PRIx64,
88 vtable_entry_addr);
89 return false;
90 }
91 addr_t vfunc_ptr = *vfunc_ptr_or_err;
92
93 vfunc_ptr = process_sp->FixCodeAddress(vfunc_ptr);
94
95 // Set our value to be the load address of the function pointer in memory
96 // and our type to be the function pointer type.
98 m_value.GetScalar() = vtable_entry_addr;
99
100 // See if our resolved address points to a function in the debug info. If
101 // it does, then we can report the type as a function prototype for this
102 // function.
103 Function *function = nullptr;
104 Address resolved_vfunc_ptr_address;
105 target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
106 if (resolved_vfunc_ptr_address.IsValid())
107 function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
108 if (function) {
109 m_value.SetCompilerType(function->GetCompilerType().GetPointerType());
110 } else {
111 // Set our value's compiler type to a generic function protoype so that
112 // it displays as a hex function pointer for the value and the summary
113 // will display the address description.
114
115 // Get the original type that this vtable is based off of so we can get
116 // the language from it correctly.
117 ValueObject *val = parent->GetParent();
118 auto type_system = target_sp->GetScratchTypeSystemForLanguage(
120 if (type_system) {
121 m_value.SetCompilerType(
122 (*type_system)->CreateGenericFunctionPrototype().GetPointerType());
123 } else {
124 consumeError(type_system.takeError());
125 }
126 }
127
128 // Now read our value into m_data so that our we can use the default
129 // summary provider for C++ for function pointers which will get the
130 // address description for our function pointer.
131 if (m_error.Success()) {
132 const bool thread_and_frame_only_if_stopped = true;
133 ExecutionContext exe_ctx(
134 GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
135 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
136 }
137 SetValueDidChange(true);
138 SetValueIsValid(true);
139 return true;
140 };
141
143 return m_value.GetCompilerType();
144 };
145
146 const uint32_t m_func_idx;
147 const uint64_t m_addr_size;
148
149private:
150 // For ValueObject only
154};
155
157 return (new ValueObjectVTable(parent))->GetSP();
158}
159
164
165llvm::Expected<uint64_t> ValueObjectVTable::GetByteSize() {
166 if (m_vtable_symbol)
167 return m_vtable_symbol->GetByteSize();
168 return llvm::createStringError("no symbol for vtable");
169}
170
171llvm::Expected<uint32_t> ValueObjectVTable::CalculateNumChildren(uint32_t max) {
172 if (UpdateValueIfNeeded(false))
173 return m_num_vtable_entries <= max ? m_num_vtable_entries : max;
174 return 0;
175}
176
178
180 if (m_vtable_symbol)
181 return m_vtable_symbol->GetName();
182 return ConstString();
183}
184
186
188 if (m_vtable_symbol)
189 return m_vtable_symbol->GetDisplayName();
190 return ConstString();
191}
192
194
198
200 m_error.Clear();
201 m_flags.m_children_count_valid = false;
202 SetValueIsValid(false);
204 ValueObject *parent = GetParent();
205 if (!parent) {
206 m_error = Status::FromErrorString("no parent object");
207 return false;
208 }
209
210 ProcessSP process_sp = GetProcessSP();
211 if (!process_sp) {
212 m_error = Status::FromErrorString("no process");
213 return false;
214 }
215
216 const LanguageType language = parent->GetObjectRuntimeLanguage();
217 LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(language);
218
219 if (language_runtime == nullptr) {
221 "no language runtime support for the language \"%s\"",
223 return false;
224 }
225
226 // Get the vtable information from the language runtime.
227 llvm::Expected<LanguageRuntime::VTableInfo> vtable_info_or_err =
228 language_runtime->GetVTableInfo(*parent, /*check_type=*/true);
229 if (!vtable_info_or_err) {
230 m_error = Status::FromError(vtable_info_or_err.takeError());
231 return false;
232 }
233
234 TargetSP target_sp = GetTargetSP();
235 const addr_t vtable_start_addr =
236 vtable_info_or_err->addr.GetLoadAddress(target_sp.get());
237
238 m_vtable_symbol = vtable_info_or_err->symbol;
239 if (!m_vtable_symbol) {
241 "no vtable symbol found containing 0x%" PRIx64, vtable_start_addr);
242 return false;
243 }
244
245 // Now that we know it's a vtable, we update the object's state.
247
248 // Calculate the number of entries
249 if (!m_vtable_symbol->GetByteSizeIsValid()) {
251 "vtable symbol \"%s\" doesn't have a valid size",
252 m_vtable_symbol->GetMangled().GetDemangledName().GetCString());
253 return false;
254 }
255
256 m_addr_size = process_sp->GetAddressByteSize();
257 const addr_t vtable_end_addr =
258 m_vtable_symbol->GetLoadAddress(target_sp.get()) +
259 m_vtable_symbol->GetByteSize();
260 m_num_vtable_entries = (vtable_end_addr - vtable_start_addr) / m_addr_size;
261
263 m_value.GetScalar() = parent->GetAddressOf().address;
264 auto type_system_or_err =
265 target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);
266 if (type_system_or_err) {
267 m_value.SetCompilerType(
268 (*type_system_or_err)->GetBasicTypeFromAST(eBasicTypeUnsignedLong));
269 } else {
270 consumeError(type_system_or_err.takeError());
271 }
272 SetValueDidChange(true);
273 SetValueIsValid(true);
274 return true;
275}
276
278
ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx, uint64_t addr_size)
llvm::Expected< uint64_t > GetByteSize() override
llvm::Expected< uint32_t > CalculateNumChildren(uint32_t max) override
Should only be called by ValueObject::GetNumChildren().
ValueObjectVTableChild(const ValueObjectVTableChild &)=delete
~ValueObjectVTableChild() override=default
CompilerType GetCompilerTypeImpl() override
const ValueObjectVTableChild & operator=(const ValueObjectVTableChild &)=delete
ValueType GetValueType() const override
A section + offset based address class.
Definition Address.h:62
Function * CalculateSymbolContextFunction() const
Definition Address.cpp:860
bool IsValid() const
Check if the object state is valid.
Definition Address.h:355
Generic representation of a type in a programming language.
CompilerType GetPointerType() const
Return a new CompilerType that is a pointer to this type.
A uniqued constant string class.
Definition ConstString.h:40
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
A class that describes a function.
Definition Function.h:377
CompilerType GetCompilerType()
Definition Function.cpp:587
virtual llvm::Expected< VTableInfo > GetVTableInfo(ValueObject &in_value, bool check_type)
Get the vtable information for a given value.
static const char * GetNameForLanguageType(lldb::LanguageType language)
Returns the internal LLDB name for the specified language.
Definition Language.cpp:305
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
static Status FromErrorString(const char *str)
Definition Status.h:141
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:136
const Symbol * m_vtable_symbol
The symbol for the C++ virtual function table.
llvm::Expected< uint32_t > CalculateNumChildren(uint32_t max) override
Should only be called by ValueObject::GetNumChildren().
uint32_t m_addr_size
Cache the address size in bytes to avoid checking with the process to many times.
ConstString GetQualifiedTypeName() override
ValueObject * CreateChildAtIndex(size_t idx) override
Should only be called by ValueObject::GetChildAtIndex().
static lldb::ValueObjectSP Create(ValueObject &parent)
lldb::ValueType GetValueType() const override
uint32_t m_num_vtable_entries
Cache the number of vtable children when we update the value.
ConstString GetDisplayTypeName() override
CompilerType GetCompilerTypeImpl() override
llvm::Expected< uint64_t > GetByteSize() override
void SetValueIsValid(bool valid)
struct lldb_private::ValueObject::Bitflags m_flags
ValueObject(ExecutionContextScope *exe_scope, ValueObjectManager &manager, AddressType child_ptr_or_ref_addr_type=eAddressTypeLoad)
Use this constructor to create a "root variable object".
Status m_error
An error object that can describe any errors that occur when updating values.
lldb::ProcessSP GetProcessSP() const
DataExtractor m_data
A data extractor that can be used to extract the value.
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
void SetValueDidChange(bool value_changed)
virtual lldb::ModuleSP GetModule()
Return the module associated with this value object in case the value is from an executable file and ...
lldb::LanguageType GetObjectRuntimeLanguage()
void SetName(llvm::StringRef name)
Change the name of the current ValueObject.
bool UpdateValueIfNeeded(bool update_format=true)
lldb::TargetSP GetTargetSP() const
virtual ValueObject * GetParent()
virtual void SetFormat(lldb::Format format)
const ExecutionContextRef & GetExecutionContextRef() const
virtual AddrAndType GetAddressOf(bool scalar_is_load_address=true)
@ LoadAddress
A load address value.
Definition Value.h:50
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
@ eBasicTypeUnsignedLong
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
LanguageType
Programming language type.
@ eLanguageTypeC_plus_plus
ISO C++:1998.
std::shared_ptr< lldb_private::Process > ProcessSP
@ eValueTypeVTableEntry
function pointer in virtual function table
@ eValueTypeVTable
virtual function table
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP