Path: blob/main/contrib/llvm-project/lldb/source/ValueObject/ValueObjectMemory.cpp
213764 views
//===-- ValueObjectMemory.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/ValueObjectMemory.h"9#include "lldb/Core/Value.h"10#include "lldb/Symbol/Type.h"11#include "lldb/Target/ExecutionContext.h"12#include "lldb/Target/Target.h"13#include "lldb/Utility/DataExtractor.h"14#include "lldb/Utility/Scalar.h"15#include "lldb/Utility/Status.h"16#include "lldb/ValueObject/ValueObject.h"17#include "lldb/lldb-types.h"18#include "llvm/Support/ErrorHandling.h"1920#include <cassert>21#include <memory>22#include <optional>2324namespace lldb_private {25class ExecutionContextScope;26}2728using namespace lldb;29using namespace lldb_private;3031ValueObjectSP ValueObjectMemory::Create(ExecutionContextScope *exe_scope,32llvm::StringRef name,33const Address &address,34lldb::TypeSP &type_sp) {35auto manager_sp = ValueObjectManager::Create();36return (new ValueObjectMemory(exe_scope, *manager_sp, name, address, type_sp))37->GetSP();38}3940ValueObjectSP ValueObjectMemory::Create(ExecutionContextScope *exe_scope,41llvm::StringRef name,42const Address &address,43const CompilerType &ast_type) {44auto manager_sp = ValueObjectManager::Create();45return (new ValueObjectMemory(exe_scope, *manager_sp, name, address,46ast_type))47->GetSP();48}4950ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope,51ValueObjectManager &manager,52llvm::StringRef name,53const Address &address,54lldb::TypeSP &type_sp)55: ValueObject(exe_scope, manager), m_address(address), m_type_sp(type_sp),56m_compiler_type() {57// Do not attempt to construct one of these objects with no variable!58assert(m_type_sp.get() != nullptr);59SetName(ConstString(name));60m_value.SetContext(Value::ContextType::LLDBType, m_type_sp.get());61TargetSP target_sp(GetTargetSP());62lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());63if (load_address != LLDB_INVALID_ADDRESS) {64m_value.SetValueType(Value::ValueType::LoadAddress);65m_value.GetScalar() = load_address;66} else {67lldb::addr_t file_address = m_address.GetFileAddress();68if (file_address != LLDB_INVALID_ADDRESS) {69m_value.SetValueType(Value::ValueType::FileAddress);70m_value.GetScalar() = file_address;71} else {72m_value.GetScalar() = m_address.GetOffset();73m_value.SetValueType(Value::ValueType::Scalar);74}75}76}7778ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope,79ValueObjectManager &manager,80llvm::StringRef name,81const Address &address,82const CompilerType &ast_type)83: ValueObject(exe_scope, manager), m_address(address), m_type_sp(),84m_compiler_type(ast_type) {85// Do not attempt to construct one of these objects with no variable!86assert(m_compiler_type.IsValid());8788TargetSP target_sp(GetTargetSP());8990SetName(ConstString(name));91m_value.SetCompilerType(m_compiler_type);92lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());93if (load_address != LLDB_INVALID_ADDRESS) {94m_value.SetValueType(Value::ValueType::LoadAddress);95m_value.GetScalar() = load_address;96} else {97lldb::addr_t file_address = m_address.GetFileAddress();98if (file_address != LLDB_INVALID_ADDRESS) {99m_value.SetValueType(Value::ValueType::FileAddress);100m_value.GetScalar() = file_address;101} else {102m_value.GetScalar() = m_address.GetOffset();103m_value.SetValueType(Value::ValueType::Scalar);104}105}106}107108ValueObjectMemory::~ValueObjectMemory() = default;109110CompilerType ValueObjectMemory::GetCompilerTypeImpl() {111if (m_type_sp)112return m_type_sp->GetForwardCompilerType();113return m_compiler_type;114}115116ConstString ValueObjectMemory::GetTypeName() {117if (m_type_sp)118return m_type_sp->GetName();119return m_compiler_type.GetTypeName();120}121122ConstString ValueObjectMemory::GetDisplayTypeName() {123if (m_type_sp)124return m_type_sp->GetForwardCompilerType().GetDisplayTypeName();125return m_compiler_type.GetDisplayTypeName();126}127128llvm::Expected<uint32_t> ValueObjectMemory::CalculateNumChildren(uint32_t max) {129if (m_type_sp) {130auto child_count = m_type_sp->GetNumChildren(true);131if (!child_count)132return child_count;133return *child_count <= max ? *child_count : max;134}135136ExecutionContext exe_ctx(GetExecutionContextRef());137const bool omit_empty_base_classes = true;138auto child_count =139m_compiler_type.GetNumChildren(omit_empty_base_classes, &exe_ctx);140if (!child_count)141return child_count;142return *child_count <= max ? *child_count : max;143}144145llvm::Expected<uint64_t> ValueObjectMemory::GetByteSize() {146ExecutionContext exe_ctx(GetExecutionContextRef());147if (m_type_sp) {148if (auto size =149m_type_sp->GetByteSize(exe_ctx.GetBestExecutionContextScope()))150return *size;151return llvm::createStringError("could not get byte size of memory object");152}153return m_compiler_type.GetByteSize(exe_ctx.GetBestExecutionContextScope());154}155156lldb::ValueType ValueObjectMemory::GetValueType() const {157// RETHINK: Should this be inherited from somewhere?158return lldb::eValueTypeVariableGlobal;159}160161bool ValueObjectMemory::UpdateValue() {162SetValueIsValid(false);163m_error.Clear();164165ExecutionContext exe_ctx(GetExecutionContextRef());166167Target *target = exe_ctx.GetTargetPtr();168if (target) {169m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());170m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());171}172173Value old_value(m_value);174if (m_address.IsValid()) {175Value::ValueType value_type = m_value.GetValueType();176177switch (value_type) {178case Value::ValueType::Invalid:179m_error = Status::FromErrorString("Invalid value");180return false;181case Value::ValueType::Scalar:182// The variable value is in the Scalar value inside the m_value. We can183// point our m_data right to it.184m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());185break;186187case Value::ValueType::FileAddress:188case Value::ValueType::LoadAddress:189case Value::ValueType::HostAddress:190// The DWARF expression result was an address in the inferior process. If191// this variable is an aggregate type, we just need the address as the192// main value as all child variable objects will rely upon this location193// and add an offset and then read their own values as needed. If this194// variable is a simple type, we read all data for it into m_data. Make195// sure this type has a value before we try and read it196197// If we have a file address, convert it to a load address if we can.198if (value_type == Value::ValueType::FileAddress &&199exe_ctx.GetProcessPtr()) {200lldb::addr_t load_addr = m_address.GetLoadAddress(target);201if (load_addr != LLDB_INVALID_ADDRESS) {202m_value.SetValueType(Value::ValueType::LoadAddress);203m_value.GetScalar() = load_addr;204}205}206207if (!CanProvideValue()) {208// this value object represents an aggregate type whose children have209// values, but this object does not. So we say we are changed if our210// location has changed.211SetValueDidChange(value_type != old_value.GetValueType() ||212m_value.GetScalar() != old_value.GetScalar());213} else {214// Copy the Value and set the context to use our Variable so it can215// extract read its value into m_data appropriately216Value value(m_value);217if (m_type_sp)218value.SetContext(Value::ContextType::LLDBType, m_type_sp.get());219else {220value.SetCompilerType(m_compiler_type);221}222223m_error = value.GetValueAsData(&exe_ctx, m_data, GetModule().get());224}225break;226}227228SetValueIsValid(m_error.Success());229}230return m_error.Success();231}232233bool ValueObjectMemory::IsInScope() {234// FIXME: Maybe try to read the memory address, and if that works, then235// we are in scope?236return true;237}238239lldb::ModuleSP ValueObjectMemory::GetModule() { return m_address.GetModule(); }240241242