xref: /freebsd/contrib/llvm-project/lldb/source/ValueObject/ValueObjectVTable.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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:
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   llvm::Expected<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 = 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 
GetCompilerTypeImpl()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 
Create(ValueObject & parent)148 ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) {
149   return (new ValueObjectVTable(parent))->GetSP();
150 }
151 
ValueObjectVTable(ValueObject & parent)152 ValueObjectVTable::ValueObjectVTable(ValueObject &parent)
153     : ValueObject(parent) {
154   SetFormat(eFormatPointer);
155 }
156 
GetByteSize()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 
CalculateNumChildren(uint32_t max)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 
GetValueType() const169 ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; }
170 
GetTypeName()171 ConstString ValueObjectVTable::GetTypeName() {
172   if (m_vtable_symbol)
173     return m_vtable_symbol->GetName();
174   return ConstString();
175 }
176 
GetQualifiedTypeName()177 ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); }
178 
GetDisplayTypeName()179 ConstString ValueObjectVTable::GetDisplayTypeName() {
180   if (m_vtable_symbol)
181     return m_vtable_symbol->GetDisplayName();
182   return ConstString();
183 }
184 
IsInScope()185 bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); }
186 
CreateChildAtIndex(size_t idx)187 ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx) {
188   return new ValueObjectVTableChild(*this, idx, m_addr_size);
189 }
190 
UpdateValue()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 
GetCompilerTypeImpl()269 CompilerType ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); }
270 
271 ValueObjectVTable::~ValueObjectVTable() = default;
272