xref: /freebsd-src/contrib/llvm-project/lldb/source/Core/ValueObjectVTable.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15f757f3fSDimitry Andric //===-- ValueObjectVTable.cpp ---------------------------------------------===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric 
95f757f3fSDimitry Andric #include "lldb/Core/ValueObjectVTable.h"
105f757f3fSDimitry Andric #include "lldb/Core/Module.h"
115f757f3fSDimitry Andric #include "lldb/Core/ValueObjectChild.h"
125f757f3fSDimitry Andric #include "lldb/Symbol/Function.h"
135f757f3fSDimitry Andric #include "lldb/Target/Language.h"
145f757f3fSDimitry Andric #include "lldb/Target/LanguageRuntime.h"
155f757f3fSDimitry Andric #include "lldb/lldb-defines.h"
165f757f3fSDimitry Andric #include "lldb/lldb-enumerations.h"
175f757f3fSDimitry Andric #include "lldb/lldb-forward.h"
185f757f3fSDimitry Andric #include "lldb/lldb-private-enumerations.h"
195f757f3fSDimitry Andric 
205f757f3fSDimitry Andric using namespace lldb;
215f757f3fSDimitry Andric using namespace lldb_private;
225f757f3fSDimitry Andric 
235f757f3fSDimitry Andric class ValueObjectVTableChild : public ValueObject {
245f757f3fSDimitry Andric public:
255f757f3fSDimitry Andric   ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,
265f757f3fSDimitry Andric                          uint64_t addr_size)
275f757f3fSDimitry Andric       : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {
285f757f3fSDimitry Andric     SetFormat(eFormatPointer);
295f757f3fSDimitry Andric     SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));
305f757f3fSDimitry Andric   }
315f757f3fSDimitry Andric 
325f757f3fSDimitry Andric   ~ValueObjectVTableChild() override = default;
335f757f3fSDimitry Andric 
345f757f3fSDimitry Andric   std::optional<uint64_t> GetByteSize() override { return m_addr_size; };
355f757f3fSDimitry Andric 
36*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override {
37*0fca6ea1SDimitry Andric     return 0;
38*0fca6ea1SDimitry Andric   };
395f757f3fSDimitry Andric 
405f757f3fSDimitry Andric   ValueType GetValueType() const override { return eValueTypeVTableEntry; };
415f757f3fSDimitry Andric 
425f757f3fSDimitry Andric   bool IsInScope() override {
435f757f3fSDimitry Andric     if (ValueObject *parent = GetParent())
445f757f3fSDimitry Andric       return parent->IsInScope();
455f757f3fSDimitry Andric     return false;
465f757f3fSDimitry Andric   };
475f757f3fSDimitry Andric 
485f757f3fSDimitry Andric protected:
495f757f3fSDimitry Andric   bool UpdateValue() override {
505f757f3fSDimitry Andric     SetValueIsValid(false);
515f757f3fSDimitry Andric     m_value.Clear();
525f757f3fSDimitry Andric     ValueObject *parent = GetParent();
535f757f3fSDimitry Andric     if (!parent) {
545f757f3fSDimitry Andric       m_error.SetErrorString("owning vtable object not valid");
555f757f3fSDimitry Andric       return false;
565f757f3fSDimitry Andric     }
575f757f3fSDimitry Andric 
585f757f3fSDimitry Andric     addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
595f757f3fSDimitry Andric     if (parent_addr == LLDB_INVALID_ADDRESS) {
605f757f3fSDimitry Andric       m_error.SetErrorString("invalid vtable address");
615f757f3fSDimitry Andric       return false;
625f757f3fSDimitry Andric     }
635f757f3fSDimitry Andric 
645f757f3fSDimitry Andric     ProcessSP process_sp = GetProcessSP();
655f757f3fSDimitry Andric     if (!process_sp) {
665f757f3fSDimitry Andric       m_error.SetErrorString("no process");
675f757f3fSDimitry Andric       return false;
685f757f3fSDimitry Andric     }
695f757f3fSDimitry Andric 
705f757f3fSDimitry Andric     TargetSP target_sp = GetTargetSP();
715f757f3fSDimitry Andric     if (!target_sp) {
725f757f3fSDimitry Andric       m_error.SetErrorString("no target");
735f757f3fSDimitry Andric       return false;
745f757f3fSDimitry Andric     }
755f757f3fSDimitry Andric 
765f757f3fSDimitry Andric     // Each `vtable_entry_addr` points to the function pointer.
775f757f3fSDimitry Andric     addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;
785f757f3fSDimitry Andric     addr_t vfunc_ptr =
795f757f3fSDimitry Andric         process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);
805f757f3fSDimitry Andric     if (m_error.Fail()) {
815f757f3fSDimitry Andric       m_error.SetErrorStringWithFormat(
825f757f3fSDimitry Andric           "failed to read virtual function entry 0x%16.16" PRIx64,
835f757f3fSDimitry Andric           vtable_entry_addr);
845f757f3fSDimitry Andric       return false;
855f757f3fSDimitry Andric     }
865f757f3fSDimitry Andric 
875f757f3fSDimitry Andric 
885f757f3fSDimitry Andric     // Set our value to be the load address of the function pointer in memory
895f757f3fSDimitry Andric     // and our type to be the function pointer type.
905f757f3fSDimitry Andric     m_value.SetValueType(Value::ValueType::LoadAddress);
915f757f3fSDimitry Andric     m_value.GetScalar() = vtable_entry_addr;
925f757f3fSDimitry Andric 
935f757f3fSDimitry Andric     // See if our resolved address points to a function in the debug info. If
945f757f3fSDimitry Andric     // it does, then we can report the type as a function prototype for this
955f757f3fSDimitry Andric     // function.
965f757f3fSDimitry Andric     Function *function = nullptr;
975f757f3fSDimitry Andric     Address resolved_vfunc_ptr_address;
985f757f3fSDimitry Andric     target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);
995f757f3fSDimitry Andric     if (resolved_vfunc_ptr_address.IsValid())
1005f757f3fSDimitry Andric       function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction();
1015f757f3fSDimitry Andric     if (function) {
1025f757f3fSDimitry Andric       m_value.SetCompilerType(function->GetCompilerType().GetPointerType());
1035f757f3fSDimitry Andric     } else {
1045f757f3fSDimitry Andric       // Set our value's compiler type to a generic function protoype so that
1055f757f3fSDimitry Andric       // it displays as a hex function pointer for the value and the summary
1065f757f3fSDimitry Andric       // will display the address description.
1075f757f3fSDimitry Andric 
1085f757f3fSDimitry Andric       // Get the original type that this vtable is based off of so we can get
1095f757f3fSDimitry Andric       // the language from it correctly.
1105f757f3fSDimitry Andric       ValueObject *val = parent->GetParent();
1115f757f3fSDimitry Andric       auto type_system = target_sp->GetScratchTypeSystemForLanguage(
1125f757f3fSDimitry Andric             val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus);
1135f757f3fSDimitry Andric       if (type_system) {
1145f757f3fSDimitry Andric         m_value.SetCompilerType(
1155f757f3fSDimitry Andric             (*type_system)->CreateGenericFunctionPrototype().GetPointerType());
1165f757f3fSDimitry Andric       } else {
1175f757f3fSDimitry Andric         consumeError(type_system.takeError());
1185f757f3fSDimitry Andric       }
1195f757f3fSDimitry Andric     }
1205f757f3fSDimitry Andric 
1215f757f3fSDimitry Andric     // Now read our value into m_data so that our we can use the default
1225f757f3fSDimitry Andric     // summary provider for C++ for function pointers which will get the
1235f757f3fSDimitry Andric     // address description for our function pointer.
1245f757f3fSDimitry Andric     if (m_error.Success()) {
1255f757f3fSDimitry Andric       const bool thread_and_frame_only_if_stopped = true;
1265f757f3fSDimitry Andric       ExecutionContext exe_ctx(
1275f757f3fSDimitry Andric         GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));
1285f757f3fSDimitry Andric       m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
1295f757f3fSDimitry Andric     }
1305f757f3fSDimitry Andric     SetValueDidChange(true);
1315f757f3fSDimitry Andric     SetValueIsValid(true);
1325f757f3fSDimitry Andric     return true;
1335f757f3fSDimitry Andric   };
1345f757f3fSDimitry Andric 
1355f757f3fSDimitry Andric   CompilerType GetCompilerTypeImpl() override {
1365f757f3fSDimitry Andric     return m_value.GetCompilerType();
1375f757f3fSDimitry Andric   };
1385f757f3fSDimitry Andric 
1395f757f3fSDimitry Andric   const uint32_t m_func_idx;
1405f757f3fSDimitry Andric   const uint64_t m_addr_size;
1415f757f3fSDimitry Andric 
1425f757f3fSDimitry Andric private:
1435f757f3fSDimitry Andric   // For ValueObject only
1445f757f3fSDimitry Andric   ValueObjectVTableChild(const ValueObjectVTableChild &) = delete;
1455f757f3fSDimitry Andric   const ValueObjectVTableChild &
1465f757f3fSDimitry Andric   operator=(const ValueObjectVTableChild &) = delete;
1475f757f3fSDimitry Andric };
1485f757f3fSDimitry Andric 
1495f757f3fSDimitry Andric ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) {
1505f757f3fSDimitry Andric   return (new ValueObjectVTable(parent))->GetSP();
1515f757f3fSDimitry Andric }
1525f757f3fSDimitry Andric 
1535f757f3fSDimitry Andric ValueObjectVTable::ValueObjectVTable(ValueObject &parent)
1545f757f3fSDimitry Andric     : ValueObject(parent) {
1555f757f3fSDimitry Andric   SetFormat(eFormatPointer);
1565f757f3fSDimitry Andric }
1575f757f3fSDimitry Andric 
1585f757f3fSDimitry Andric std::optional<uint64_t> ValueObjectVTable::GetByteSize() {
1595f757f3fSDimitry Andric   if (m_vtable_symbol)
1605f757f3fSDimitry Andric     return m_vtable_symbol->GetByteSize();
1615f757f3fSDimitry Andric   return std::nullopt;
1625f757f3fSDimitry Andric }
1635f757f3fSDimitry Andric 
164*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> ValueObjectVTable::CalculateNumChildren(uint32_t max) {
1655f757f3fSDimitry Andric   if (UpdateValueIfNeeded(false))
1665f757f3fSDimitry Andric     return m_num_vtable_entries <= max ? m_num_vtable_entries : max;
1675f757f3fSDimitry Andric   return 0;
1685f757f3fSDimitry Andric }
1695f757f3fSDimitry Andric 
1705f757f3fSDimitry Andric ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; }
1715f757f3fSDimitry Andric 
1725f757f3fSDimitry Andric ConstString ValueObjectVTable::GetTypeName() {
1735f757f3fSDimitry Andric   if (m_vtable_symbol)
1745f757f3fSDimitry Andric     return m_vtable_symbol->GetName();
1755f757f3fSDimitry Andric   return ConstString();
1765f757f3fSDimitry Andric }
1775f757f3fSDimitry Andric 
1785f757f3fSDimitry Andric ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); }
1795f757f3fSDimitry Andric 
1805f757f3fSDimitry Andric ConstString ValueObjectVTable::GetDisplayTypeName() {
1815f757f3fSDimitry Andric   if (m_vtable_symbol)
1825f757f3fSDimitry Andric     return m_vtable_symbol->GetDisplayName();
1835f757f3fSDimitry Andric   return ConstString();
1845f757f3fSDimitry Andric }
1855f757f3fSDimitry Andric 
1865f757f3fSDimitry Andric bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); }
1875f757f3fSDimitry Andric 
188*0fca6ea1SDimitry Andric ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx) {
1895f757f3fSDimitry Andric   return new ValueObjectVTableChild(*this, idx, m_addr_size);
1905f757f3fSDimitry Andric }
1915f757f3fSDimitry Andric 
1925f757f3fSDimitry Andric bool ValueObjectVTable::UpdateValue() {
1935f757f3fSDimitry Andric   m_error.Clear();
1945f757f3fSDimitry Andric   m_flags.m_children_count_valid = false;
1955f757f3fSDimitry Andric   SetValueIsValid(false);
1965f757f3fSDimitry Andric   m_num_vtable_entries = 0;
1975f757f3fSDimitry Andric   ValueObject *parent = GetParent();
1985f757f3fSDimitry Andric   if (!parent) {
1995f757f3fSDimitry Andric     m_error.SetErrorString("no parent object");
2005f757f3fSDimitry Andric     return false;
2015f757f3fSDimitry Andric   }
2025f757f3fSDimitry Andric 
2035f757f3fSDimitry Andric   ProcessSP process_sp = GetProcessSP();
2045f757f3fSDimitry Andric   if (!process_sp) {
2055f757f3fSDimitry Andric     m_error.SetErrorString("no process");
2065f757f3fSDimitry Andric     return false;
2075f757f3fSDimitry Andric   }
2085f757f3fSDimitry Andric 
2095f757f3fSDimitry Andric   const LanguageType language = parent->GetObjectRuntimeLanguage();
2105f757f3fSDimitry Andric   LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(language);
2115f757f3fSDimitry Andric 
2125f757f3fSDimitry Andric   if (language_runtime == nullptr) {
2135f757f3fSDimitry Andric     m_error.SetErrorStringWithFormat(
2145f757f3fSDimitry Andric         "no language runtime support for the language \"%s\"",
2155f757f3fSDimitry Andric         Language::GetNameForLanguageType(language));
2165f757f3fSDimitry Andric     return false;
2175f757f3fSDimitry Andric   }
2185f757f3fSDimitry Andric 
2195f757f3fSDimitry Andric   // Get the vtable information from the language runtime.
2205f757f3fSDimitry Andric   llvm::Expected<LanguageRuntime::VTableInfo> vtable_info_or_err =
2215f757f3fSDimitry Andric       language_runtime->GetVTableInfo(*parent, /*check_type=*/true);
2225f757f3fSDimitry Andric   if (!vtable_info_or_err) {
2235f757f3fSDimitry Andric     m_error = vtable_info_or_err.takeError();
2245f757f3fSDimitry Andric     return false;
2255f757f3fSDimitry Andric   }
2265f757f3fSDimitry Andric 
2275f757f3fSDimitry Andric   TargetSP target_sp = GetTargetSP();
2285f757f3fSDimitry Andric   const addr_t vtable_start_addr =
2295f757f3fSDimitry Andric       vtable_info_or_err->addr.GetLoadAddress(target_sp.get());
2305f757f3fSDimitry Andric 
2315f757f3fSDimitry Andric   m_vtable_symbol = vtable_info_or_err->symbol;
2325f757f3fSDimitry Andric   if (!m_vtable_symbol) {
2335f757f3fSDimitry Andric     m_error.SetErrorStringWithFormat(
2345f757f3fSDimitry Andric         "no vtable symbol found containing 0x%" PRIx64, vtable_start_addr);
2355f757f3fSDimitry Andric     return false;
2365f757f3fSDimitry Andric   }
2375f757f3fSDimitry Andric 
2385f757f3fSDimitry Andric   // Now that we know it's a vtable, we update the object's state.
2395f757f3fSDimitry Andric   SetName(GetTypeName());
2405f757f3fSDimitry Andric 
2415f757f3fSDimitry Andric   // Calculate the number of entries
2425f757f3fSDimitry Andric   if (!m_vtable_symbol->GetByteSizeIsValid()) {
2435f757f3fSDimitry Andric     m_error.SetErrorStringWithFormat(
2445f757f3fSDimitry Andric         "vtable symbol \"%s\" doesn't have a valid size",
2455f757f3fSDimitry Andric         m_vtable_symbol->GetMangled().GetDemangledName().GetCString());
2465f757f3fSDimitry Andric     return false;
2475f757f3fSDimitry Andric   }
2485f757f3fSDimitry Andric 
2495f757f3fSDimitry Andric   m_addr_size = process_sp->GetAddressByteSize();
2505f757f3fSDimitry Andric   const addr_t vtable_end_addr =
2515f757f3fSDimitry Andric       m_vtable_symbol->GetLoadAddress(target_sp.get()) +
2525f757f3fSDimitry Andric       m_vtable_symbol->GetByteSize();
2535f757f3fSDimitry Andric   m_num_vtable_entries = (vtable_end_addr - vtable_start_addr) / m_addr_size;
2545f757f3fSDimitry Andric 
2555f757f3fSDimitry Andric   m_value.SetValueType(Value::ValueType::LoadAddress);
2565f757f3fSDimitry Andric   m_value.GetScalar() = parent->GetAddressOf();
2575f757f3fSDimitry Andric   auto type_system_or_err =
2585f757f3fSDimitry Andric         target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);
2595f757f3fSDimitry Andric   if (type_system_or_err) {
2605f757f3fSDimitry Andric     m_value.SetCompilerType(
2615f757f3fSDimitry Andric         (*type_system_or_err)->GetBasicTypeFromAST(eBasicTypeUnsignedLong));
2625f757f3fSDimitry Andric   } else {
2635f757f3fSDimitry Andric     consumeError(type_system_or_err.takeError());
2645f757f3fSDimitry Andric   }
2655f757f3fSDimitry Andric   SetValueDidChange(true);
2665f757f3fSDimitry Andric   SetValueIsValid(true);
2675f757f3fSDimitry Andric   return true;
2685f757f3fSDimitry Andric }
2695f757f3fSDimitry Andric 
2705f757f3fSDimitry Andric CompilerType ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); }
2715f757f3fSDimitry Andric 
2725f757f3fSDimitry Andric ValueObjectVTable::~ValueObjectVTable() = default;
273