1*c9157d92SDimitry Andric //===-- ValueObjectVTable.cpp ---------------------------------------------===//
2*c9157d92SDimitry Andric //
3*c9157d92SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c9157d92SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*c9157d92SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c9157d92SDimitry Andric //
7*c9157d92SDimitry Andric //===----------------------------------------------------------------------===//
8*c9157d92SDimitry Andric
9*c9157d92SDimitry Andric #include "lldb/Core/ValueObjectVTable.h"
10*c9157d92SDimitry Andric #include "lldb/Core/Module.h"
11*c9157d92SDimitry Andric #include "lldb/Core/ValueObjectChild.h"
12*c9157d92SDimitry Andric #include "lldb/Symbol/Function.h"
13*c9157d92SDimitry Andric #include "lldb/Target/Language.h"
14*c9157d92SDimitry Andric #include "lldb/Target/LanguageRuntime.h"
15*c9157d92SDimitry Andric #include "lldb/lldb-defines.h"
16*c9157d92SDimitry Andric #include "lldb/lldb-enumerations.h"
17*c9157d92SDimitry Andric #include "lldb/lldb-forward.h"
18*c9157d92SDimitry Andric #include "lldb/lldb-private-enumerations.h"
19*c9157d92SDimitry Andric
20*c9157d92SDimitry Andric using namespace lldb;
21*c9157d92SDimitry Andric using namespace lldb_private;
22*c9157d92SDimitry Andric
23*c9157d92SDimitry Andric class ValueObjectVTableChild : public ValueObject {
24*c9157d92SDimitry Andric public:
ValueObjectVTableChild(ValueObject & parent,uint32_t func_idx,uint64_t addr_size)25*c9157d92SDimitry Andric ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
26*c9157d92SDimitry Andric uint64_t addr_size)
27*c9157d92SDimitry Andric : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
28*c9157d92SDimitry Andric SetFormat(eFormatPointer);
29*c9157d92SDimitry Andric SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
30*c9157d92SDimitry Andric }
31*c9157d92SDimitry Andric
32*c9157d92SDimitry Andric ~ValueObjectVTableChild() override = default;
33*c9157d92SDimitry Andric
GetByteSize()34*c9157d92SDimitry Andric std::optional<uint64_t> GetByteSize() override { return m_addr_size; };
35*c9157d92SDimitry Andric
CalculateNumChildren(uint32_t max)36*c9157d92SDimitry Andric size_t CalculateNumChildren(uint32_t max) override { return 0; };
37*c9157d92SDimitry Andric
GetValueType() const38*c9157d92SDimitry Andric ValueType GetValueType() const override { return eValueTypeVTableEntry; };
39*c9157d92SDimitry Andric
IsInScope()40*c9157d92SDimitry Andric bool IsInScope() override {
41*c9157d92SDimitry Andric if (ValueObject *parent = GetParent())
42*c9157d92SDimitry Andric return parent->IsInScope();
43*c9157d92SDimitry Andric return false;
44*c9157d92SDimitry Andric };
45*c9157d92SDimitry Andric
46*c9157d92SDimitry Andric protected:
UpdateValue()47*c9157d92SDimitry Andric bool UpdateValue() override {
48*c9157d92SDimitry Andric SetValueIsValid(false);
49*c9157d92SDimitry Andric m_value.Clear();
50*c9157d92SDimitry Andric ValueObject *parent = GetParent();
51*c9157d92SDimitry Andric if (!parent) {
52*c9157d92SDimitry Andric m_error.SetErrorString("owning vtable object not valid");
53*c9157d92SDimitry Andric return false;
54*c9157d92SDimitry Andric }
55*c9157d92SDimitry Andric
56*c9157d92SDimitry Andric addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
57*c9157d92SDimitry Andric if (parent_addr == LLDB_INVALID_ADDRESS) {
58*c9157d92SDimitry Andric m_error.SetErrorString("invalid vtable address");
59*c9157d92SDimitry Andric return false;
60*c9157d92SDimitry Andric }
61*c9157d92SDimitry Andric
62*c9157d92SDimitry Andric ProcessSP process_sp = GetProcessSP();
63*c9157d92SDimitry Andric if (!process_sp) {
64*c9157d92SDimitry Andric m_error.SetErrorString("no process");
65*c9157d92SDimitry Andric return false;
66*c9157d92SDimitry Andric }
67*c9157d92SDimitry Andric
68*c9157d92SDimitry Andric TargetSP target_sp = GetTargetSP();
69*c9157d92SDimitry Andric if (!target_sp) {
70*c9157d92SDimitry Andric m_error.SetErrorString("no target");
71*c9157d92SDimitry Andric return false;
72*c9157d92SDimitry Andric }
73*c9157d92SDimitry Andric
74*c9157d92SDimitry Andric // Each `vtable_entry_addr` points to the function pointer.
75*c9157d92SDimitry Andric addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
76*c9157d92SDimitry Andric addr_t vfunc_ptr =
77*c9157d92SDimitry Andric process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
78*c9157d92SDimitry Andric if (m_error.Fail()) {
79*c9157d92SDimitry Andric m_error.SetErrorStringWithFormat(
80*c9157d92SDimitry Andric "failed to read virtual function entry 0x%16.16" PRIx64,
81*c9157d92SDimitry Andric vtable_entry_addr);
82*c9157d92SDimitry Andric return false;
83*c9157d92SDimitry Andric }
84*c9157d92SDimitry Andric
85*c9157d92SDimitry Andric
86*c9157d92SDimitry Andric // Set our value to be the load address of the function pointer in memory
87*c9157d92SDimitry Andric // and our type to be the function pointer type.
88*c9157d92SDimitry Andric m_value.SetValueType(Value::ValueType::LoadAddress);
89*c9157d92SDimitry Andric m_value.GetScalar() = vtable_entry_addr;
90*c9157d92SDimitry Andric
91*c9157d92SDimitry Andric // See if our resolved address points to a function in the debug info. If
92*c9157d92SDimitry Andric // it does, then we can report the type as a function prototype for this
93*c9157d92SDimitry Andric // function.
94*c9157d92SDimitry Andric Function *function = nullptr;
95*c9157d92SDimitry Andric Address resolved_vfunc_ptr_address;
96*c9157d92SDimitry Andric target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
97*c9157d92SDimitry Andric if (resolved_vfunc_ptr_address.IsValid())
98*c9157d92SDimitry Andric function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
99*c9157d92SDimitry Andric if (function) {
100*c9157d92SDimitry Andric m_value.SetCompilerType(function->GetCompilerType().GetPointerType());
101*c9157d92SDimitry Andric } else {
102*c9157d92SDimitry Andric // Set our value's compiler type to a generic function protoype so that
103*c9157d92SDimitry Andric // it displays as a hex function pointer for the value and the summary
104*c9157d92SDimitry Andric // will display the address description.
105*c9157d92SDimitry Andric
106*c9157d92SDimitry Andric // Get the original type that this vtable is based off of so we can get
107*c9157d92SDimitry Andric // the language from it correctly.
108*c9157d92SDimitry Andric ValueObject *val = parent->GetParent();
109*c9157d92SDimitry Andric auto type_system = target_sp->GetScratchTypeSystemForLanguage(
110*c9157d92SDimitry Andric val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus);
111*c9157d92SDimitry Andric if (type_system) {
112*c9157d92SDimitry Andric m_value.SetCompilerType(
113*c9157d92SDimitry Andric (*type_system)->CreateGenericFunctionPrototype().GetPointerType());
114*c9157d92SDimitry Andric } else {
115*c9157d92SDimitry Andric consumeError(type_system.takeError());
116*c9157d92SDimitry Andric }
117*c9157d92SDimitry Andric }
118*c9157d92SDimitry Andric
119*c9157d92SDimitry Andric // Now read our value into m_data so that our we can use the default
120*c9157d92SDimitry Andric // summary provider for C++ for function pointers which will get the
121*c9157d92SDimitry Andric // address description for our function pointer.
122*c9157d92SDimitry Andric if (m_error.Success()) {
123*c9157d92SDimitry Andric const bool thread_and_frame_only_if_stopped = true;
124*c9157d92SDimitry Andric ExecutionContext exe_ctx(
125*c9157d92SDimitry Andric GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
126*c9157d92SDimitry Andric m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
127*c9157d92SDimitry Andric }
128*c9157d92SDimitry Andric SetValueDidChange(true);
129*c9157d92SDimitry Andric SetValueIsValid(true);
130*c9157d92SDimitry Andric return true;
131*c9157d92SDimitry Andric };
132*c9157d92SDimitry Andric
GetCompilerTypeImpl()133*c9157d92SDimitry Andric CompilerType GetCompilerTypeImpl() override {
134*c9157d92SDimitry Andric return m_value.GetCompilerType();
135*c9157d92SDimitry Andric };
136*c9157d92SDimitry Andric
137*c9157d92SDimitry Andric const uint32_t m_func_idx;
138*c9157d92SDimitry Andric const uint64_t m_addr_size;
139*c9157d92SDimitry Andric
140*c9157d92SDimitry Andric private:
141*c9157d92SDimitry Andric // For ValueObject only
142*c9157d92SDimitry Andric ValueObjectVTableChild(const ValueObjectVTableChild &) = delete;
143*c9157d92SDimitry Andric const ValueObjectVTableChild &
144*c9157d92SDimitry Andric operator=(const ValueObjectVTableChild &) = delete;
145*c9157d92SDimitry Andric };
146*c9157d92SDimitry Andric
Create(ValueObject & parent)147*c9157d92SDimitry Andric ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) {
148*c9157d92SDimitry Andric return (new ValueObjectVTable(parent))->GetSP();
149*c9157d92SDimitry Andric }
150*c9157d92SDimitry Andric
ValueObjectVTable(ValueObject & parent)151*c9157d92SDimitry Andric ValueObjectVTable::ValueObjectVTable(ValueObject &parent)
152*c9157d92SDimitry Andric : ValueObject(parent) {
153*c9157d92SDimitry Andric SetFormat(eFormatPointer);
154*c9157d92SDimitry Andric }
155*c9157d92SDimitry Andric
GetByteSize()156*c9157d92SDimitry Andric std::optional<uint64_t> ValueObjectVTable::GetByteSize() {
157*c9157d92SDimitry Andric if (m_vtable_symbol)
158*c9157d92SDimitry Andric return m_vtable_symbol->GetByteSize();
159*c9157d92SDimitry Andric return std::nullopt;
160*c9157d92SDimitry Andric }
161*c9157d92SDimitry Andric
CalculateNumChildren(uint32_t max)162*c9157d92SDimitry Andric size_t ValueObjectVTable::CalculateNumChildren(uint32_t max) {
163*c9157d92SDimitry Andric if (UpdateValueIfNeeded(false))
164*c9157d92SDimitry Andric return m_num_vtable_entries <= max ? m_num_vtable_entries : max;
165*c9157d92SDimitry Andric return 0;
166*c9157d92SDimitry Andric }
167*c9157d92SDimitry Andric
GetValueType() const168*c9157d92SDimitry Andric ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; }
169*c9157d92SDimitry Andric
GetTypeName()170*c9157d92SDimitry Andric ConstString ValueObjectVTable::GetTypeName() {
171*c9157d92SDimitry Andric if (m_vtable_symbol)
172*c9157d92SDimitry Andric return m_vtable_symbol->GetName();
173*c9157d92SDimitry Andric return ConstString();
174*c9157d92SDimitry Andric }
175*c9157d92SDimitry Andric
GetQualifiedTypeName()176*c9157d92SDimitry Andric ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); }
177*c9157d92SDimitry Andric
GetDisplayTypeName()178*c9157d92SDimitry Andric ConstString ValueObjectVTable::GetDisplayTypeName() {
179*c9157d92SDimitry Andric if (m_vtable_symbol)
180*c9157d92SDimitry Andric return m_vtable_symbol->GetDisplayName();
181*c9157d92SDimitry Andric return ConstString();
182*c9157d92SDimitry Andric }
183*c9157d92SDimitry Andric
IsInScope()184*c9157d92SDimitry Andric bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); }
185*c9157d92SDimitry Andric
CreateChildAtIndex(size_t idx,bool synthetic_array_member,int32_t synthetic_index)186*c9157d92SDimitry Andric ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx,
187*c9157d92SDimitry Andric bool synthetic_array_member,
188*c9157d92SDimitry Andric int32_t synthetic_index) {
189*c9157d92SDimitry Andric if (synthetic_array_member)
190*c9157d92SDimitry Andric return nullptr;
191*c9157d92SDimitry Andric return new ValueObjectVTableChild(*this, idx, m_addr_size);
192*c9157d92SDimitry Andric }
193*c9157d92SDimitry Andric
UpdateValue()194*c9157d92SDimitry Andric bool ValueObjectVTable::UpdateValue() {
195*c9157d92SDimitry Andric m_error.Clear();
196*c9157d92SDimitry Andric m_flags.m_children_count_valid = false;
197*c9157d92SDimitry Andric SetValueIsValid(false);
198*c9157d92SDimitry Andric m_num_vtable_entries = 0;
199*c9157d92SDimitry Andric ValueObject *parent = GetParent();
200*c9157d92SDimitry Andric if (!parent) {
201*c9157d92SDimitry Andric m_error.SetErrorString("no parent object");
202*c9157d92SDimitry Andric return false;
203*c9157d92SDimitry Andric }
204*c9157d92SDimitry Andric
205*c9157d92SDimitry Andric ProcessSP process_sp = GetProcessSP();
206*c9157d92SDimitry Andric if (!process_sp) {
207*c9157d92SDimitry Andric m_error.SetErrorString("no process");
208*c9157d92SDimitry Andric return false;
209*c9157d92SDimitry Andric }
210*c9157d92SDimitry Andric
211*c9157d92SDimitry Andric const LanguageType language = parent->GetObjectRuntimeLanguage();
212*c9157d92SDimitry Andric LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(language);
213*c9157d92SDimitry Andric
214*c9157d92SDimitry Andric if (language_runtime == nullptr) {
215*c9157d92SDimitry Andric m_error.SetErrorStringWithFormat(
216*c9157d92SDimitry Andric "no language runtime support for the language \"%s\"",
217*c9157d92SDimitry Andric Language::GetNameForLanguageType(language));
218*c9157d92SDimitry Andric return false;
219*c9157d92SDimitry Andric }
220*c9157d92SDimitry Andric
221*c9157d92SDimitry Andric // Get the vtable information from the language runtime.
222*c9157d92SDimitry Andric llvm::Expected<LanguageRuntime::VTableInfo> vtable_info_or_err =
223*c9157d92SDimitry Andric language_runtime->GetVTableInfo(*parent, /*check_type=*/true);
224*c9157d92SDimitry Andric if (!vtable_info_or_err) {
225*c9157d92SDimitry Andric m_error = vtable_info_or_err.takeError();
226*c9157d92SDimitry Andric return false;
227*c9157d92SDimitry Andric }
228*c9157d92SDimitry Andric
229*c9157d92SDimitry Andric TargetSP target_sp = GetTargetSP();
230*c9157d92SDimitry Andric const addr_t vtable_start_addr =
231*c9157d92SDimitry Andric vtable_info_or_err->addr.GetLoadAddress(target_sp.get());
232*c9157d92SDimitry Andric
233*c9157d92SDimitry Andric m_vtable_symbol = vtable_info_or_err->symbol;
234*c9157d92SDimitry Andric if (!m_vtable_symbol) {
235*c9157d92SDimitry Andric m_error.SetErrorStringWithFormat(
236*c9157d92SDimitry Andric "no vtable symbol found containing 0x%" PRIx64, vtable_start_addr);
237*c9157d92SDimitry Andric return false;
238*c9157d92SDimitry Andric }
239*c9157d92SDimitry Andric
240*c9157d92SDimitry Andric // Now that we know it's a vtable, we update the object's state.
241*c9157d92SDimitry Andric SetName(GetTypeName());
242*c9157d92SDimitry Andric
243*c9157d92SDimitry Andric // Calculate the number of entries
244*c9157d92SDimitry Andric if (!m_vtable_symbol->GetByteSizeIsValid()) {
245*c9157d92SDimitry Andric m_error.SetErrorStringWithFormat(
246*c9157d92SDimitry Andric "vtable symbol \"%s\" doesn't have a valid size",
247*c9157d92SDimitry Andric m_vtable_symbol->GetMangled().GetDemangledName().GetCString());
248*c9157d92SDimitry Andric return false;
249*c9157d92SDimitry Andric }
250*c9157d92SDimitry Andric
251*c9157d92SDimitry Andric m_addr_size = process_sp->GetAddressByteSize();
252*c9157d92SDimitry Andric const addr_t vtable_end_addr =
253*c9157d92SDimitry Andric m_vtable_symbol->GetLoadAddress(target_sp.get()) +
254*c9157d92SDimitry Andric m_vtable_symbol->GetByteSize();
255*c9157d92SDimitry Andric m_num_vtable_entries = (vtable_end_addr - vtable_start_addr) / m_addr_size;
256*c9157d92SDimitry Andric
257*c9157d92SDimitry Andric m_value.SetValueType(Value::ValueType::LoadAddress);
258*c9157d92SDimitry Andric m_value.GetScalar() = parent->GetAddressOf();
259*c9157d92SDimitry Andric auto type_system_or_err =
260*c9157d92SDimitry Andric target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);
261*c9157d92SDimitry Andric if (type_system_or_err) {
262*c9157d92SDimitry Andric m_value.SetCompilerType(
263*c9157d92SDimitry Andric (*type_system_or_err)->GetBasicTypeFromAST(eBasicTypeUnsignedLong));
264*c9157d92SDimitry Andric } else {
265*c9157d92SDimitry Andric consumeError(type_system_or_err.takeError());
266*c9157d92SDimitry Andric }
267*c9157d92SDimitry Andric SetValueDidChange(true);
268*c9157d92SDimitry Andric SetValueIsValid(true);
269*c9157d92SDimitry Andric return true;
270*c9157d92SDimitry Andric }
271*c9157d92SDimitry Andric
GetCompilerTypeImpl()272*c9157d92SDimitry Andric CompilerType ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); }
273*c9157d92SDimitry Andric
274*c9157d92SDimitry Andric ValueObjectVTable::~ValueObjectVTable() = default;
275