Path: blob/main/contrib/llvm-project/lldb/source/ValueObject/ValueObjectVariable.cpp
213764 views
//===-- ValueObjectVariable.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/ValueObjectVariable.h"910#include "lldb/Core/Address.h"11#include "lldb/Core/AddressRange.h"12#include "lldb/Core/Declaration.h"13#include "lldb/Core/Module.h"14#include "lldb/Core/Value.h"15#include "lldb/Expression/DWARFExpressionList.h"16#include "lldb/Symbol/Function.h"17#include "lldb/Symbol/ObjectFile.h"18#include "lldb/Symbol/SymbolContext.h"19#include "lldb/Symbol/SymbolContextScope.h"20#include "lldb/Symbol/Type.h"21#include "lldb/Symbol/Variable.h"22#include "lldb/Target/ExecutionContext.h"23#include "lldb/Target/Process.h"24#include "lldb/Target/RegisterContext.h"25#include "lldb/Target/Target.h"26#include "lldb/Utility/DataExtractor.h"27#include "lldb/Utility/RegisterValue.h"28#include "lldb/Utility/Scalar.h"29#include "lldb/Utility/Status.h"30#include "lldb/lldb-private-enumerations.h"31#include "lldb/lldb-types.h"3233#include "llvm/ADT/StringRef.h"3435#include <cassert>36#include <memory>37#include <optional>3839namespace lldb_private {40class ExecutionContextScope;41}42namespace lldb_private {43class StackFrame;44}45namespace lldb_private {46struct RegisterInfo;47}48using namespace lldb_private;4950lldb::ValueObjectSP51ValueObjectVariable::Create(ExecutionContextScope *exe_scope,52const lldb::VariableSP &var_sp) {53auto manager_sp = ValueObjectManager::Create();54return (new ValueObjectVariable(exe_scope, *manager_sp, var_sp))->GetSP();55}5657ValueObjectVariable::ValueObjectVariable(ExecutionContextScope *exe_scope,58ValueObjectManager &manager,59const lldb::VariableSP &var_sp)60: ValueObject(exe_scope, manager), m_variable_sp(var_sp) {61// Do not attempt to construct one of these objects with no variable!62assert(m_variable_sp.get() != nullptr);63m_name = var_sp->GetName();64}6566ValueObjectVariable::~ValueObjectVariable() = default;6768CompilerType ValueObjectVariable::GetCompilerTypeImpl() {69Type *var_type = m_variable_sp->GetType();70if (var_type)71return var_type->GetForwardCompilerType();72return CompilerType();73}7475ConstString ValueObjectVariable::GetTypeName() {76Type *var_type = m_variable_sp->GetType();77if (var_type)78return var_type->GetName();79return ConstString();80}8182ConstString ValueObjectVariable::GetDisplayTypeName() {83Type *var_type = m_variable_sp->GetType();84if (var_type)85return var_type->GetForwardCompilerType().GetDisplayTypeName();86return ConstString();87}8889ConstString ValueObjectVariable::GetQualifiedTypeName() {90Type *var_type = m_variable_sp->GetType();91if (var_type)92return var_type->GetQualifiedName();93return ConstString();94}9596llvm::Expected<uint32_t>97ValueObjectVariable::CalculateNumChildren(uint32_t max) {98CompilerType type(GetCompilerType());99100if (!type.IsValid())101return llvm::make_error<llvm::StringError>("invalid type",102llvm::inconvertibleErrorCode());103104ExecutionContext exe_ctx(GetExecutionContextRef());105const bool omit_empty_base_classes = true;106auto child_count = type.GetNumChildren(omit_empty_base_classes, &exe_ctx);107if (!child_count)108return child_count;109return *child_count <= max ? *child_count : max;110}111112llvm::Expected<uint64_t> ValueObjectVariable::GetByteSize() {113ExecutionContext exe_ctx(GetExecutionContextRef());114115CompilerType type(GetCompilerType());116return type.GetByteSize(exe_ctx.GetBestExecutionContextScope());117}118119lldb::ValueType ValueObjectVariable::GetValueType() const {120if (m_variable_sp)121return m_variable_sp->GetScope();122return lldb::eValueTypeInvalid;123}124125bool ValueObjectVariable::UpdateValue() {126SetValueIsValid(false);127m_error.Clear();128129Variable *variable = m_variable_sp.get();130DWARFExpressionList &expr_list = variable->LocationExpressionList();131132if (variable->GetLocationIsConstantValueData()) {133// expr doesn't contain DWARF bytes, it contains the constant variable134// value bytes themselves...135if (expr_list.GetExpressionData(m_data)) {136if (m_data.GetDataStart() && m_data.GetByteSize())137m_value.SetBytes(m_data.GetDataStart(), m_data.GetByteSize());138m_value.SetContext(Value::ContextType::Variable, variable);139} else140m_error = Status::FromErrorString("empty constant data");141// constant bytes can't be edited - sorry142m_resolved_value.SetContext(Value::ContextType::Invalid, nullptr);143} else {144lldb::addr_t loclist_base_load_addr = LLDB_INVALID_ADDRESS;145ExecutionContext exe_ctx(GetExecutionContextRef());146147Target *target = exe_ctx.GetTargetPtr();148if (target) {149m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());150m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());151}152153if (!expr_list.IsAlwaysValidSingleExpr()) {154SymbolContext sc;155variable->CalculateSymbolContext(&sc);156if (sc.function)157loclist_base_load_addr =158sc.function->GetAddress().GetLoadAddress(target);159}160Value old_value(m_value);161llvm::Expected<Value> maybe_value = expr_list.Evaluate(162&exe_ctx, nullptr, loclist_base_load_addr, nullptr, nullptr);163164if (maybe_value) {165m_value = *maybe_value;166m_resolved_value = m_value;167m_value.SetContext(Value::ContextType::Variable, variable);168169CompilerType compiler_type = GetCompilerType();170if (compiler_type.IsValid())171m_value.SetCompilerType(compiler_type);172173Value::ValueType value_type = m_value.GetValueType();174175// The size of the buffer within m_value can be less than the size176// prescribed by its type. E.g. this can happen when an expression only177// partially describes an object (say, because it contains DW_OP_piece).178//179// In this case, grow m_value to the expected size. An alternative way to180// handle this is to teach Value::GetValueAsData() and ValueObjectChild181// not to read past the end of a host buffer, but this gets impractically182// complicated as a Value's host buffer may be shared with a distant183// ancestor or sibling in the ValueObject hierarchy.184//185// FIXME: When we grow m_value, we should represent the added bits as186// undefined somehow instead of as 0's.187if (value_type == Value::ValueType::HostAddress &&188compiler_type.IsValid()) {189if (size_t value_buf_size = m_value.GetBuffer().GetByteSize()) {190size_t value_size = m_value.GetValueByteSize(&m_error, &exe_ctx);191if (m_error.Success() && value_buf_size < value_size)192m_value.ResizeData(value_size);193}194}195196Process *process = exe_ctx.GetProcessPtr();197const bool process_is_alive = process && process->IsAlive();198199switch (value_type) {200case Value::ValueType::Invalid:201m_error = Status::FromErrorString("invalid value");202break;203case Value::ValueType::Scalar:204// The variable value is in the Scalar value inside the m_value. We can205// point our m_data right to it.206m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());207break;208209case Value::ValueType::FileAddress:210case Value::ValueType::LoadAddress:211case Value::ValueType::HostAddress:212// The DWARF expression result was an address in the inferior process.213// If this variable is an aggregate type, we just need the address as214// the main value as all child variable objects will rely upon this215// location and add an offset and then read their own values as needed.216// If this variable is a simple type, we read all data for it into217// m_data. Make sure this type has a value before we try and read it218219// If we have a file address, convert it to a load address if we can.220if (value_type == Value::ValueType::FileAddress && process_is_alive)221m_value.ConvertToLoadAddress(GetModule().get(), target);222223if (!CanProvideValue()) {224// this value object represents an aggregate type whose children have225// values, but this object does not. So we say we are changed if our226// location has changed.227SetValueDidChange(value_type != old_value.GetValueType() ||228m_value.GetScalar() != old_value.GetScalar());229} else {230// Copy the Value and set the context to use our Variable so it can231// extract read its value into m_data appropriately232Value value(m_value);233value.SetContext(Value::ContextType::Variable, variable);234m_error = value.GetValueAsData(&exe_ctx, m_data, GetModule().get());235236SetValueDidChange(value_type != old_value.GetValueType() ||237m_value.GetScalar() != old_value.GetScalar());238}239break;240}241242SetValueIsValid(m_error.Success());243} else {244m_error = Status::FromError(maybe_value.takeError());245// could not find location, won't allow editing246m_resolved_value.SetContext(Value::ContextType::Invalid, nullptr);247}248}249250return m_error.Success();251}252253void ValueObjectVariable::DoUpdateChildrenAddressType(ValueObject &valobj) {254Value::ValueType value_type = valobj.GetValue().GetValueType();255ExecutionContext exe_ctx(GetExecutionContextRef());256Process *process = exe_ctx.GetProcessPtr();257const bool process_is_alive = process && process->IsAlive();258const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();259const bool is_pointer_or_ref =260(type_info & (lldb::eTypeIsPointer | lldb::eTypeIsReference)) != 0;261262switch (value_type) {263case Value::ValueType::Invalid:264break;265case Value::ValueType::FileAddress:266// If this type is a pointer, then its children will be considered load267// addresses if the pointer or reference is dereferenced, but only if268// the process is alive.269//270// There could be global variables like in the following code:271// struct LinkedListNode { Foo* foo; LinkedListNode* next; };272// Foo g_foo1;273// Foo g_foo2;274// LinkedListNode g_second_node = { &g_foo2, NULL };275// LinkedListNode g_first_node = { &g_foo1, &g_second_node };276//277// When we aren't running, we should be able to look at these variables278// using the "target variable" command. Children of the "g_first_node"279// always will be of the same address type as the parent. But children280// of the "next" member of LinkedListNode will become load addresses if281// we have a live process, or remain a file address if it was a file282// address.283if (process_is_alive && is_pointer_or_ref)284valobj.SetAddressTypeOfChildren(eAddressTypeLoad);285else286valobj.SetAddressTypeOfChildren(eAddressTypeFile);287break;288case Value::ValueType::HostAddress:289// Same as above for load addresses, except children of pointer or refs290// are always load addresses. Host addresses are used to store freeze291// dried variables. If this type is a struct, the entire struct292// contents will be copied into the heap of the293// LLDB process, but we do not currently follow any pointers.294if (is_pointer_or_ref)295valobj.SetAddressTypeOfChildren(eAddressTypeLoad);296else297valobj.SetAddressTypeOfChildren(eAddressTypeHost);298break;299case Value::ValueType::LoadAddress:300case Value::ValueType::Scalar:301valobj.SetAddressTypeOfChildren(eAddressTypeLoad);302break;303}304}305306bool ValueObjectVariable::IsInScope() {307const ExecutionContextRef &exe_ctx_ref = GetExecutionContextRef();308if (exe_ctx_ref.HasFrameRef()) {309ExecutionContext exe_ctx(exe_ctx_ref);310StackFrame *frame = exe_ctx.GetFramePtr();311if (frame) {312return m_variable_sp->IsInScope(frame);313} else {314// This ValueObject had a frame at one time, but now we can't locate it,315// so return false since we probably aren't in scope.316return false;317}318}319// We have a variable that wasn't tied to a frame, which means it is a global320// and is always in scope.321return true;322}323324lldb::ModuleSP ValueObjectVariable::GetModule() {325if (m_variable_sp) {326SymbolContextScope *sc_scope = m_variable_sp->GetSymbolContextScope();327if (sc_scope) {328return sc_scope->CalculateSymbolContextModule();329}330}331return lldb::ModuleSP();332}333334SymbolContextScope *ValueObjectVariable::GetSymbolContextScope() {335if (m_variable_sp)336return m_variable_sp->GetSymbolContextScope();337return nullptr;338}339340bool ValueObjectVariable::GetDeclaration(Declaration &decl) {341if (m_variable_sp) {342decl = m_variable_sp->GetDeclaration();343return true;344}345return false;346}347348const char *ValueObjectVariable::GetLocationAsCString() {349if (m_resolved_value.GetContextType() == Value::ContextType::RegisterInfo)350return GetLocationAsCStringImpl(m_resolved_value, m_data);351else352return ValueObject::GetLocationAsCString();353}354355bool ValueObjectVariable::SetValueFromCString(const char *value_str,356Status &error) {357if (!UpdateValueIfNeeded()) {358error = Status::FromErrorString("unable to update value before writing");359return false;360}361362if (m_resolved_value.GetContextType() == Value::ContextType::RegisterInfo) {363RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo();364ExecutionContext exe_ctx(GetExecutionContextRef());365RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();366RegisterValue reg_value;367if (!reg_info || !reg_ctx) {368error = Status::FromErrorString("unable to retrieve register info");369return false;370}371error = reg_value.SetValueFromString(reg_info, llvm::StringRef(value_str));372if (error.Fail())373return false;374if (reg_ctx->WriteRegister(reg_info, reg_value)) {375SetNeedsUpdate();376return true;377} else {378error = Status::FromErrorString("unable to write back to register");379return false;380}381} else382return ValueObject::SetValueFromCString(value_str, error);383}384385bool ValueObjectVariable::SetData(DataExtractor &data, Status &error) {386if (!UpdateValueIfNeeded()) {387error = Status::FromErrorString("unable to update value before writing");388return false;389}390391if (m_resolved_value.GetContextType() == Value::ContextType::RegisterInfo) {392RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo();393ExecutionContext exe_ctx(GetExecutionContextRef());394RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();395RegisterValue reg_value;396if (!reg_info || !reg_ctx) {397error = Status::FromErrorString("unable to retrieve register info");398return false;399}400error = reg_value.SetValueFromData(*reg_info, data, 0, true);401if (error.Fail())402return false;403if (reg_ctx->WriteRegister(reg_info, reg_value)) {404SetNeedsUpdate();405return true;406} else {407error = Status::FromErrorString("unable to write back to register");408return false;409}410} else411return ValueObject::SetData(data, error);412}413414415