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
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"
19
20using namespace lldb;
21using namespace lldb_private;
22
23class ValueObjectVTableChild : public ValueObject {
24public:
25 ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
26 uint64_t addr_size)
27 : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
28 SetFormat(eFormatPointer);
29 SetName(ConstString(llvm::formatv(Fmt: "[{0}]", Vals&: func_idx).str()));
30 }
31
32 ~ValueObjectVTableChild() override = default;
33
34 llvm::Expected<uint64_t> GetByteSize() override { return m_addr_size; };
35
36 llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override {
37 return 0;
38 };
39
40 ValueType GetValueType() const override { return eValueTypeVTableEntry; };
41
42 bool IsInScope() override {
43 if (ValueObject *parent = GetParent())
44 return parent->IsInScope();
45 return false;
46 };
47
48protected:
49 bool UpdateValue() override {
50 SetValueIsValid(false);
51 m_value.Clear();
52 ValueObject *parent = GetParent();
53 if (!parent) {
54 m_error = Status::FromErrorString(str: "owning vtable object not valid");
55 return false;
56 }
57
58 addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
59 if (parent_addr == LLDB_INVALID_ADDRESS) {
60 m_error = Status::FromErrorString(str: "invalid vtable address");
61 return false;
62 }
63
64 ProcessSP process_sp = GetProcessSP();
65 if (!process_sp) {
66 m_error = Status::FromErrorString(str: "no process");
67 return false;
68 }
69
70 TargetSP target_sp = GetTargetSP();
71 if (!target_sp) {
72 m_error = Status::FromErrorString(str: "no target");
73 return false;
74 }
75
76 // Each `vtable_entry_addr` points to the function pointer.
77 addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
78 addr_t vfunc_ptr =
79 process_sp->ReadPointerFromMemory(vm_addr: vtable_entry_addr, error&: m_error);
80 if (m_error.Fail()) {
81 m_error = Status::FromErrorStringWithFormat(
82 format: "failed to read virtual function entry 0x%16.16" PRIx64,
83 vtable_entry_addr);
84 return false;
85 }
86
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;
91
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
94 // function.
95 Function *function = nullptr;
96 Address resolved_vfunc_ptr_address;
97 target_sp->ResolveLoadAddress(load_addr: vfunc_ptr, so_addr&: resolved_vfunc_ptr_address);
98 if (resolved_vfunc_ptr_address.IsValid())
99 function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
100 if (function) {
101 m_value.SetCompilerType(function->GetCompilerType().GetPointerType());
102 } else {
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.
106
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 language: val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus);
112 if (type_system) {
113 m_value.SetCompilerType(
114 (*type_system)->CreateGenericFunctionPrototype().GetPointerType());
115 } else {
116 consumeError(Err: type_system.takeError());
117 }
118 }
119
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: &exe_ctx, data&: m_data, module: GetModule().get());
128 }
129 SetValueDidChange(true);
130 SetValueIsValid(true);
131 return true;
132 };
133
134 CompilerType GetCompilerTypeImpl() override {
135 return m_value.GetCompilerType();
136 };
137
138 const uint32_t m_func_idx;
139 const uint64_t m_addr_size;
140
141private:
142 // For ValueObject only
143 ValueObjectVTableChild(const ValueObjectVTableChild &) = delete;
144 const ValueObjectVTableChild &
145 operator=(const ValueObjectVTableChild &) = delete;
146};
147
148ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) {
149 return (new ValueObjectVTable(parent))->GetSP();
150}
151
152ValueObjectVTable::ValueObjectVTable(ValueObject &parent)
153 : ValueObject(parent) {
154 SetFormat(eFormatPointer);
155}
156
157llvm::Expected<uint64_t> ValueObjectVTable::GetByteSize() {
158 if (m_vtable_symbol)
159 return m_vtable_symbol->GetByteSize();
160 return llvm::createStringError(Fmt: "no symbol for vtable");
161}
162
163llvm::Expected<uint32_t> ValueObjectVTable::CalculateNumChildren(uint32_t max) {
164 if (UpdateValueIfNeeded(update_format: false))
165 return m_num_vtable_entries <= max ? m_num_vtable_entries : max;
166 return 0;
167}
168
169ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; }
170
171ConstString ValueObjectVTable::GetTypeName() {
172 if (m_vtable_symbol)
173 return m_vtable_symbol->GetName();
174 return ConstString();
175}
176
177ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); }
178
179ConstString ValueObjectVTable::GetDisplayTypeName() {
180 if (m_vtable_symbol)
181 return m_vtable_symbol->GetDisplayName();
182 return ConstString();
183}
184
185bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); }
186
187ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx) {
188 return new ValueObjectVTableChild(*this, idx, m_addr_size);
189}
190
191bool ValueObjectVTable::UpdateValue() {
192 m_error.Clear();
193 m_flags.m_children_count_valid = false;
194 SetValueIsValid(false);
195 m_num_vtable_entries = 0;
196 ValueObject *parent = GetParent();
197 if (!parent) {
198 m_error = Status::FromErrorString(str: "no parent object");
199 return false;
200 }
201
202 ProcessSP process_sp = GetProcessSP();
203 if (!process_sp) {
204 m_error = Status::FromErrorString(str: "no process");
205 return false;
206 }
207
208 const LanguageType language = parent->GetObjectRuntimeLanguage();
209 LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(language);
210
211 if (language_runtime == nullptr) {
212 m_error = Status::FromErrorStringWithFormat(
213 format: "no language runtime support for the language \"%s\"",
214 Language::GetNameForLanguageType(language));
215 return false;
216 }
217
218 // Get the vtable information from the language runtime.
219 llvm::Expected<LanguageRuntime::VTableInfo> vtable_info_or_err =
220 language_runtime->GetVTableInfo(in_value&: *parent, /*check_type=*/true);
221 if (!vtable_info_or_err) {
222 m_error = Status::FromError(error: vtable_info_or_err.takeError());
223 return false;
224 }
225
226 TargetSP target_sp = GetTargetSP();
227 const addr_t vtable_start_addr =
228 vtable_info_or_err->addr.GetLoadAddress(target: target_sp.get());
229
230 m_vtable_symbol = vtable_info_or_err->symbol;
231 if (!m_vtable_symbol) {
232 m_error = Status::FromErrorStringWithFormat(
233 format: "no vtable symbol found containing 0x%" PRIx64, vtable_start_addr);
234 return false;
235 }
236
237 // Now that we know it's a vtable, we update the object's state.
238 SetName(GetTypeName());
239
240 // Calculate the number of entries
241 if (!m_vtable_symbol->GetByteSizeIsValid()) {
242 m_error = Status::FromErrorStringWithFormat(
243 format: "vtable symbol \"%s\" doesn't have a valid size",
244 m_vtable_symbol->GetMangled().GetDemangledName().GetCString());
245 return false;
246 }
247
248 m_addr_size = process_sp->GetAddressByteSize();
249 const addr_t vtable_end_addr =
250 m_vtable_symbol->GetLoadAddress(target: target_sp.get()) +
251 m_vtable_symbol->GetByteSize();
252 m_num_vtable_entries = (vtable_end_addr - vtable_start_addr) / m_addr_size;
253
254 m_value.SetValueType(Value::ValueType::LoadAddress);
255 m_value.GetScalar() = parent->GetAddressOf().address;
256 auto type_system_or_err =
257 target_sp->GetScratchTypeSystemForLanguage(language: eLanguageTypeC_plus_plus);
258 if (type_system_or_err) {
259 m_value.SetCompilerType(
260 (*type_system_or_err)->GetBasicTypeFromAST(basic_type: eBasicTypeUnsignedLong));
261 } else {
262 consumeError(Err: type_system_or_err.takeError());
263 }
264 SetValueDidChange(true);
265 SetValueIsValid(true);
266 return true;
267}
268
269CompilerType ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); }
270
271ValueObjectVTable::~ValueObjectVTable() = default;
272

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/source/ValueObject/ValueObjectVTable.cpp