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