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