241 lines · cpp
1//===-- ValueObjectMemory.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/ValueObjectMemory.h"10#include "lldb/Core/Value.h"11#include "lldb/Symbol/Type.h"12#include "lldb/Target/ExecutionContext.h"13#include "lldb/Target/Target.h"14#include "lldb/Utility/DataExtractor.h"15#include "lldb/Utility/Scalar.h"16#include "lldb/Utility/Status.h"17#include "lldb/ValueObject/ValueObject.h"18#include "lldb/lldb-types.h"19#include "llvm/Support/ErrorHandling.h"20 21#include <cassert>22#include <memory>23#include <optional>24 25namespace lldb_private {26class ExecutionContextScope;27}28 29using namespace lldb;30using namespace lldb_private;31 32ValueObjectSP ValueObjectMemory::Create(ExecutionContextScope *exe_scope,33 llvm::StringRef name,34 const Address &address,35 lldb::TypeSP &type_sp) {36 auto manager_sp = ValueObjectManager::Create();37 return (new ValueObjectMemory(exe_scope, *manager_sp, name, address, type_sp))38 ->GetSP();39}40 41ValueObjectSP ValueObjectMemory::Create(ExecutionContextScope *exe_scope,42 llvm::StringRef name,43 const Address &address,44 const CompilerType &ast_type) {45 auto manager_sp = ValueObjectManager::Create();46 return (new ValueObjectMemory(exe_scope, *manager_sp, name, address,47 ast_type))48 ->GetSP();49}50 51ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope,52 ValueObjectManager &manager,53 llvm::StringRef name,54 const Address &address,55 lldb::TypeSP &type_sp)56 : ValueObject(exe_scope, manager), m_address(address), m_type_sp(type_sp),57 m_compiler_type() {58 // Do not attempt to construct one of these objects with no variable!59 assert(m_type_sp.get() != nullptr);60 SetName(ConstString(name));61 m_value.SetContext(Value::ContextType::LLDBType, m_type_sp.get());62 TargetSP target_sp(GetTargetSP());63 lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());64 if (load_address != LLDB_INVALID_ADDRESS) {65 m_value.SetValueType(Value::ValueType::LoadAddress);66 m_value.GetScalar() = load_address;67 } else {68 lldb::addr_t file_address = m_address.GetFileAddress();69 if (file_address != LLDB_INVALID_ADDRESS) {70 m_value.SetValueType(Value::ValueType::FileAddress);71 m_value.GetScalar() = file_address;72 } else {73 m_value.GetScalar() = m_address.GetOffset();74 m_value.SetValueType(Value::ValueType::Scalar);75 }76 }77}78 79ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope,80 ValueObjectManager &manager,81 llvm::StringRef name,82 const Address &address,83 const CompilerType &ast_type)84 : ValueObject(exe_scope, manager), m_address(address), m_type_sp(),85 m_compiler_type(ast_type) {86 // Do not attempt to construct one of these objects with no variable!87 assert(m_compiler_type.IsValid());88 89 TargetSP target_sp(GetTargetSP());90 91 SetName(ConstString(name));92 m_value.SetCompilerType(m_compiler_type);93 lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());94 if (load_address != LLDB_INVALID_ADDRESS) {95 m_value.SetValueType(Value::ValueType::LoadAddress);96 m_value.GetScalar() = load_address;97 } else {98 lldb::addr_t file_address = m_address.GetFileAddress();99 if (file_address != LLDB_INVALID_ADDRESS) {100 m_value.SetValueType(Value::ValueType::FileAddress);101 m_value.GetScalar() = file_address;102 } else {103 m_value.GetScalar() = m_address.GetOffset();104 m_value.SetValueType(Value::ValueType::Scalar);105 }106 }107}108 109ValueObjectMemory::~ValueObjectMemory() = default;110 111CompilerType ValueObjectMemory::GetCompilerTypeImpl() {112 if (m_type_sp)113 return m_type_sp->GetForwardCompilerType();114 return m_compiler_type;115}116 117ConstString ValueObjectMemory::GetTypeName() {118 if (m_type_sp)119 return m_type_sp->GetName();120 return m_compiler_type.GetTypeName();121}122 123ConstString ValueObjectMemory::GetDisplayTypeName() {124 if (m_type_sp)125 return m_type_sp->GetForwardCompilerType().GetDisplayTypeName();126 return m_compiler_type.GetDisplayTypeName();127}128 129llvm::Expected<uint32_t> ValueObjectMemory::CalculateNumChildren(uint32_t max) {130 if (m_type_sp) {131 auto child_count = m_type_sp->GetNumChildren(true);132 if (!child_count)133 return child_count;134 return *child_count <= max ? *child_count : max;135 }136 137 ExecutionContext exe_ctx(GetExecutionContextRef());138 const bool omit_empty_base_classes = true;139 auto child_count =140 m_compiler_type.GetNumChildren(omit_empty_base_classes, &exe_ctx);141 if (!child_count)142 return child_count;143 return *child_count <= max ? *child_count : max;144}145 146llvm::Expected<uint64_t> ValueObjectMemory::GetByteSize() {147 ExecutionContext exe_ctx(GetExecutionContextRef());148 if (m_type_sp) {149 if (auto size =150 m_type_sp->GetByteSize(exe_ctx.GetBestExecutionContextScope()))151 return *size;152 return llvm::createStringError("could not get byte size of memory object");153 }154 return m_compiler_type.GetByteSize(exe_ctx.GetBestExecutionContextScope());155}156 157lldb::ValueType ValueObjectMemory::GetValueType() const {158 // RETHINK: Should this be inherited from somewhere?159 return lldb::eValueTypeVariableGlobal;160}161 162bool ValueObjectMemory::UpdateValue() {163 SetValueIsValid(false);164 m_error.Clear();165 166 ExecutionContext exe_ctx(GetExecutionContextRef());167 168 Target *target = exe_ctx.GetTargetPtr();169 if (target) {170 m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());171 m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());172 }173 174 Value old_value(m_value);175 if (m_address.IsValid()) {176 Value::ValueType value_type = m_value.GetValueType();177 178 switch (value_type) {179 case Value::ValueType::Invalid:180 m_error = Status::FromErrorString("Invalid value");181 return false;182 case Value::ValueType::Scalar:183 // The variable value is in the Scalar value inside the m_value. We can184 // point our m_data right to it.185 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());186 break;187 188 case Value::ValueType::FileAddress:189 case Value::ValueType::LoadAddress:190 case Value::ValueType::HostAddress:191 // The DWARF expression result was an address in the inferior process. If192 // this variable is an aggregate type, we just need the address as the193 // main value as all child variable objects will rely upon this location194 // and add an offset and then read their own values as needed. If this195 // variable is a simple type, we read all data for it into m_data. Make196 // sure this type has a value before we try and read it197 198 // If we have a file address, convert it to a load address if we can.199 if (value_type == Value::ValueType::FileAddress &&200 exe_ctx.GetProcessPtr()) {201 lldb::addr_t load_addr = m_address.GetLoadAddress(target);202 if (load_addr != LLDB_INVALID_ADDRESS) {203 m_value.SetValueType(Value::ValueType::LoadAddress);204 m_value.GetScalar() = load_addr;205 }206 }207 208 if (!CanProvideValue()) {209 // this value object represents an aggregate type whose children have210 // values, but this object does not. So we say we are changed if our211 // location has changed.212 SetValueDidChange(value_type != old_value.GetValueType() ||213 m_value.GetScalar() != old_value.GetScalar());214 } else {215 // Copy the Value and set the context to use our Variable so it can216 // extract read its value into m_data appropriately217 Value value(m_value);218 if (m_type_sp)219 value.SetContext(Value::ContextType::LLDBType, m_type_sp.get());220 else {221 value.SetCompilerType(m_compiler_type);222 }223 224 m_error = value.GetValueAsData(&exe_ctx, m_data, GetModule().get());225 }226 break;227 }228 229 SetValueIsValid(m_error.Success());230 }231 return m_error.Success();232}233 234bool ValueObjectMemory::IsInScope() {235 // FIXME: Maybe try to read the memory address, and if that works, then236 // we are in scope?237 return true;238}239 240lldb::ModuleSP ValueObjectMemory::GetModule() { return m_address.GetModule(); }241