Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/ValueObject/ValueObjectVTable.cpp
213764 views
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
20
using namespace lldb;
21
using namespace lldb_private;
22
23
class ValueObjectVTableChild : public ValueObject {
24
public:
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("[{0}]", 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
48
protected:
49
bool UpdateValue() override {
50
SetValueIsValid(false);
51
m_value.Clear();
52
ValueObject *parent = GetParent();
53
if (!parent) {
54
m_error = Status::FromErrorString("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("invalid vtable address");
61
return false;
62
}
63
64
ProcessSP process_sp = GetProcessSP();
65
if (!process_sp) {
66
m_error = Status::FromErrorString("no process");
67
return false;
68
}
69
70
TargetSP target_sp = GetTargetSP();
71
if (!target_sp) {
72
m_error = Status::FromErrorString("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(vtable_entry_addr, m_error);
80
if (m_error.Fail()) {
81
m_error = Status::FromErrorStringWithFormat(
82
"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(vfunc_ptr, 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
val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus);
112
if (type_system) {
113
m_value.SetCompilerType(
114
(*type_system)->CreateGenericFunctionPrototype().GetPointerType());
115
} else {
116
consumeError(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, m_data, 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
141
private:
142
// For ValueObject only
143
ValueObjectVTableChild(const ValueObjectVTableChild &) = delete;
144
const ValueObjectVTableChild &
145
operator=(const ValueObjectVTableChild &) = delete;
146
};
147
148
ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) {
149
return (new ValueObjectVTable(parent))->GetSP();
150
}
151
152
ValueObjectVTable::ValueObjectVTable(ValueObject &parent)
153
: ValueObject(parent) {
154
SetFormat(eFormatPointer);
155
}
156
157
llvm::Expected<uint64_t> ValueObjectVTable::GetByteSize() {
158
if (m_vtable_symbol)
159
return m_vtable_symbol->GetByteSize();
160
return llvm::createStringError("no symbol for vtable");
161
}
162
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;
166
return 0;
167
}
168
169
ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; }
170
171
ConstString ValueObjectVTable::GetTypeName() {
172
if (m_vtable_symbol)
173
return m_vtable_symbol->GetName();
174
return ConstString();
175
}
176
177
ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); }
178
179
ConstString ValueObjectVTable::GetDisplayTypeName() {
180
if (m_vtable_symbol)
181
return m_vtable_symbol->GetDisplayName();
182
return ConstString();
183
}
184
185
bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); }
186
187
ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx) {
188
return new ValueObjectVTableChild(*this, idx, m_addr_size);
189
}
190
191
bool 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("no parent object");
199
return false;
200
}
201
202
ProcessSP process_sp = GetProcessSP();
203
if (!process_sp) {
204
m_error = Status::FromErrorString("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
"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(*parent, /*check_type=*/true);
221
if (!vtable_info_or_err) {
222
m_error = Status::FromError(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_sp.get());
229
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);
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
"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_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(eLanguageTypeC_plus_plus);
258
if (type_system_or_err) {
259
m_value.SetCompilerType(
260
(*type_system_or_err)->GetBasicTypeFromAST(eBasicTypeUnsignedLong));
261
} else {
262
consumeError(type_system_or_err.takeError());
263
}
264
SetValueDidChange(true);
265
SetValueIsValid(true);
266
return true;
267
}
268
269
CompilerType ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); }
270
271
ValueObjectVTable::~ValueObjectVTable() = default;
272
273