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