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