Path: blob/main/contrib/llvm-project/lldb/source/ValueObject/ValueObjectVTable.cpp
213764 views
//===-- ValueObjectVTable.cpp ---------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/ValueObject/ValueObjectVTable.h"9#include "lldb/Core/Module.h"10#include "lldb/Symbol/Function.h"11#include "lldb/Target/Language.h"12#include "lldb/Target/LanguageRuntime.h"13#include "lldb/ValueObject/ValueObjectChild.h"14#include "lldb/lldb-defines.h"15#include "lldb/lldb-enumerations.h"16#include "lldb/lldb-forward.h"17#include "lldb/lldb-private-enumerations.h"1819using namespace lldb;20using namespace lldb_private;2122class ValueObjectVTableChild : public ValueObject {23public:24ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx,25uint64_t addr_size)26: ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) {27SetFormat(eFormatPointer);28SetName(ConstString(llvm::formatv("[{0}]", func_idx).str()));29}3031~ValueObjectVTableChild() override = default;3233llvm::Expected<uint64_t> GetByteSize() override { return m_addr_size; };3435llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override {36return 0;37};3839ValueType GetValueType() const override { return eValueTypeVTableEntry; };4041bool IsInScope() override {42if (ValueObject *parent = GetParent())43return parent->IsInScope();44return false;45};4647protected:48bool UpdateValue() override {49SetValueIsValid(false);50m_value.Clear();51ValueObject *parent = GetParent();52if (!parent) {53m_error = Status::FromErrorString("owning vtable object not valid");54return false;55}5657addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);58if (parent_addr == LLDB_INVALID_ADDRESS) {59m_error = Status::FromErrorString("invalid vtable address");60return false;61}6263ProcessSP process_sp = GetProcessSP();64if (!process_sp) {65m_error = Status::FromErrorString("no process");66return false;67}6869TargetSP target_sp = GetTargetSP();70if (!target_sp) {71m_error = Status::FromErrorString("no target");72return false;73}7475// Each `vtable_entry_addr` points to the function pointer.76addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size;77addr_t vfunc_ptr =78process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error);79if (m_error.Fail()) {80m_error = Status::FromErrorStringWithFormat(81"failed to read virtual function entry 0x%16.16" PRIx64,82vtable_entry_addr);83return false;84}8586// Set our value to be the load address of the function pointer in memory87// and our type to be the function pointer type.88m_value.SetValueType(Value::ValueType::LoadAddress);89m_value.GetScalar() = vtable_entry_addr;9091// See if our resolved address points to a function in the debug info. If92// it does, then we can report the type as a function prototype for this93// function.94Function *function = nullptr;95Address resolved_vfunc_ptr_address;96target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address);97if (resolved_vfunc_ptr_address.IsValid())98function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction();99if (function) {100m_value.SetCompilerType(function->GetCompilerType().GetPointerType());101} else {102// Set our value's compiler type to a generic function protoype so that103// it displays as a hex function pointer for the value and the summary104// will display the address description.105106// Get the original type that this vtable is based off of so we can get107// the language from it correctly.108ValueObject *val = parent->GetParent();109auto type_system = target_sp->GetScratchTypeSystemForLanguage(110val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus);111if (type_system) {112m_value.SetCompilerType(113(*type_system)->CreateGenericFunctionPrototype().GetPointerType());114} else {115consumeError(type_system.takeError());116}117}118119// Now read our value into m_data so that our we can use the default120// summary provider for C++ for function pointers which will get the121// address description for our function pointer.122if (m_error.Success()) {123const bool thread_and_frame_only_if_stopped = true;124ExecutionContext exe_ctx(125GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped));126m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());127}128SetValueDidChange(true);129SetValueIsValid(true);130return true;131};132133CompilerType GetCompilerTypeImpl() override {134return m_value.GetCompilerType();135};136137const uint32_t m_func_idx;138const uint64_t m_addr_size;139140private:141// For ValueObject only142ValueObjectVTableChild(const ValueObjectVTableChild &) = delete;143const ValueObjectVTableChild &144operator=(const ValueObjectVTableChild &) = delete;145};146147ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) {148return (new ValueObjectVTable(parent))->GetSP();149}150151ValueObjectVTable::ValueObjectVTable(ValueObject &parent)152: ValueObject(parent) {153SetFormat(eFormatPointer);154}155156llvm::Expected<uint64_t> ValueObjectVTable::GetByteSize() {157if (m_vtable_symbol)158return m_vtable_symbol->GetByteSize();159return llvm::createStringError("no symbol for vtable");160}161162llvm::Expected<uint32_t> ValueObjectVTable::CalculateNumChildren(uint32_t max) {163if (UpdateValueIfNeeded(false))164return m_num_vtable_entries <= max ? m_num_vtable_entries : max;165return 0;166}167168ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; }169170ConstString ValueObjectVTable::GetTypeName() {171if (m_vtable_symbol)172return m_vtable_symbol->GetName();173return ConstString();174}175176ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); }177178ConstString ValueObjectVTable::GetDisplayTypeName() {179if (m_vtable_symbol)180return m_vtable_symbol->GetDisplayName();181return ConstString();182}183184bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); }185186ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx) {187return new ValueObjectVTableChild(*this, idx, m_addr_size);188}189190bool ValueObjectVTable::UpdateValue() {191m_error.Clear();192m_flags.m_children_count_valid = false;193SetValueIsValid(false);194m_num_vtable_entries = 0;195ValueObject *parent = GetParent();196if (!parent) {197m_error = Status::FromErrorString("no parent object");198return false;199}200201ProcessSP process_sp = GetProcessSP();202if (!process_sp) {203m_error = Status::FromErrorString("no process");204return false;205}206207const LanguageType language = parent->GetObjectRuntimeLanguage();208LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(language);209210if (language_runtime == nullptr) {211m_error = Status::FromErrorStringWithFormat(212"no language runtime support for the language \"%s\"",213Language::GetNameForLanguageType(language));214return false;215}216217// Get the vtable information from the language runtime.218llvm::Expected<LanguageRuntime::VTableInfo> vtable_info_or_err =219language_runtime->GetVTableInfo(*parent, /*check_type=*/true);220if (!vtable_info_or_err) {221m_error = Status::FromError(vtable_info_or_err.takeError());222return false;223}224225TargetSP target_sp = GetTargetSP();226const addr_t vtable_start_addr =227vtable_info_or_err->addr.GetLoadAddress(target_sp.get());228229m_vtable_symbol = vtable_info_or_err->symbol;230if (!m_vtable_symbol) {231m_error = Status::FromErrorStringWithFormat(232"no vtable symbol found containing 0x%" PRIx64, vtable_start_addr);233return false;234}235236// Now that we know it's a vtable, we update the object's state.237SetName(GetTypeName());238239// Calculate the number of entries240if (!m_vtable_symbol->GetByteSizeIsValid()) {241m_error = Status::FromErrorStringWithFormat(242"vtable symbol \"%s\" doesn't have a valid size",243m_vtable_symbol->GetMangled().GetDemangledName().GetCString());244return false;245}246247m_addr_size = process_sp->GetAddressByteSize();248const addr_t vtable_end_addr =249m_vtable_symbol->GetLoadAddress(target_sp.get()) +250m_vtable_symbol->GetByteSize();251m_num_vtable_entries = (vtable_end_addr - vtable_start_addr) / m_addr_size;252253m_value.SetValueType(Value::ValueType::LoadAddress);254m_value.GetScalar() = parent->GetAddressOf().address;255auto type_system_or_err =256target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus);257if (type_system_or_err) {258m_value.SetCompilerType(259(*type_system_or_err)->GetBasicTypeFromAST(eBasicTypeUnsignedLong));260} else {261consumeError(type_system_or_err.takeError());262}263SetValueDidChange(true);264SetValueIsValid(true);265return true;266}267268CompilerType ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); }269270ValueObjectVTable::~ValueObjectVTable() = default;271272273