brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.0 KiB · 6f6ee45 Raw
272 lines · cpp
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-exception6//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 20using namespace lldb;21using namespace lldb_private;22 23class ValueObjectVTableChild : public ValueObject {24public: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 34  llvm::Expected<uint64_t> GetByteSize() override { return m_addr_size; };35 36  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override {37    return 0;38  };39 40  ValueType GetValueType() const override { return eValueTypeVTableEntry; };41 42  bool IsInScope() override {43    if (ValueObject *parent = GetParent())44      return parent->IsInScope();45    return false;46  };47 48protected: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 memory88    // 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. If93    // it does, then we can report the type as a function prototype for this94    // 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 that104      // it displays as a hex function pointer for the value and the summary105      // will display the address description.106 107      // Get the original type that this vtable is based off of so we can get108      // 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 default121    // summary provider for C++ for function pointers which will get the122    // 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 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 141private:142  // For ValueObject only143  ValueObjectVTableChild(const ValueObjectVTableChild &) = delete;144  const ValueObjectVTableChild &145  operator=(const ValueObjectVTableChild &) = delete;146};147 148ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) {149  return (new ValueObjectVTable(parent))->GetSP();150}151 152ValueObjectVTable::ValueObjectVTable(ValueObject &parent)153    : ValueObject(parent) {154  SetFormat(eFormatPointer);155}156 157llvm::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 163llvm::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 169ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; }170 171ConstString ValueObjectVTable::GetTypeName() {172  if (m_vtable_symbol)173    return m_vtable_symbol->GetName();174  return ConstString();175}176 177ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); }178 179ConstString ValueObjectVTable::GetDisplayTypeName() {180  if (m_vtable_symbol)181    return m_vtable_symbol->GetDisplayName();182  return ConstString();183}184 185bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); }186 187ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx) {188  return new ValueObjectVTableChild(*this, idx, m_addr_size);189}190 191bool 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 entries241  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 269CompilerType ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); }270 271ValueObjectVTable::~ValueObjectVTable() = default;272