Path: blob/main/contrib/llvm-project/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
213764 views
//===-- ValueObjectDynamicValue.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/ValueObjectDynamicValue.h"9#include "lldb/Core/Value.h"10#include "lldb/Symbol/CompilerType.h"11#include "lldb/Symbol/Type.h"12#include "lldb/Target/ExecutionContext.h"13#include "lldb/Target/LanguageRuntime.h"14#include "lldb/Target/Process.h"15#include "lldb/Target/Target.h"16#include "lldb/Utility/DataExtractor.h"17#include "lldb/Utility/LLDBLog.h"18#include "lldb/Utility/Log.h"19#include "lldb/Utility/Scalar.h"20#include "lldb/Utility/Status.h"21#include "lldb/ValueObject/ValueObject.h"22#include "lldb/lldb-types.h"2324#include <cstring>25#include <optional>26namespace lldb_private {27class Declaration;28}2930using namespace lldb_private;3132ValueObjectDynamicValue::ValueObjectDynamicValue(33ValueObject &parent, lldb::DynamicValueType use_dynamic)34: ValueObject(parent), m_address(), m_dynamic_type_info(),35m_use_dynamic(use_dynamic) {36SetName(parent.GetName());37}3839CompilerType ValueObjectDynamicValue::GetCompilerTypeImpl() {40const bool success = UpdateValueIfNeeded(false);41if (success) {42if (m_dynamic_type_info.HasType())43return m_value.GetCompilerType();44else45return m_parent->GetCompilerType();46}47return m_parent->GetCompilerType();48}4950ConstString ValueObjectDynamicValue::GetTypeName() {51const bool success = UpdateValueIfNeeded(false);52if (success) {53if (m_dynamic_type_info.HasName())54return m_dynamic_type_info.GetName();55}56return m_parent->GetTypeName();57}5859TypeImpl ValueObjectDynamicValue::GetTypeImpl() {60const bool success = UpdateValueIfNeeded(false);61if (success && m_type_impl.IsValid()) {62return m_type_impl;63}64return m_parent->GetTypeImpl();65}6667ConstString ValueObjectDynamicValue::GetQualifiedTypeName() {68const bool success = UpdateValueIfNeeded(false);69if (success) {70if (m_dynamic_type_info.HasName())71return m_dynamic_type_info.GetName();72}73return m_parent->GetQualifiedTypeName();74}7576ConstString ValueObjectDynamicValue::GetDisplayTypeName() {77const bool success = UpdateValueIfNeeded(false);78if (success) {79if (m_dynamic_type_info.HasType())80return GetCompilerType().GetDisplayTypeName();81if (m_dynamic_type_info.HasName())82return m_dynamic_type_info.GetName();83}84return m_parent->GetDisplayTypeName();85}8687llvm::Expected<uint32_t>88ValueObjectDynamicValue::CalculateNumChildren(uint32_t max) {89const bool success = UpdateValueIfNeeded(false);90if (success && m_dynamic_type_info.HasType()) {91ExecutionContext exe_ctx(GetExecutionContextRef());92auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx);93if (!children_count)94return children_count;95return *children_count <= max ? *children_count : max;96} else97return m_parent->GetNumChildren(max);98}99100llvm::Expected<uint64_t> ValueObjectDynamicValue::GetByteSize() {101const bool success = UpdateValueIfNeeded(false);102if (success && m_dynamic_type_info.HasType()) {103ExecutionContext exe_ctx(GetExecutionContextRef());104return m_value.GetValueByteSize(nullptr, &exe_ctx);105} else106return m_parent->GetByteSize();107}108109lldb::ValueType ValueObjectDynamicValue::GetValueType() const {110return m_parent->GetValueType();111}112113bool ValueObjectDynamicValue::UpdateValue() {114SetValueIsValid(false);115m_error.Clear();116117if (!m_parent->UpdateValueIfNeeded(false)) {118// The dynamic value failed to get an error, pass the error along119if (m_error.Success() && m_parent->GetError().Fail())120m_error = m_parent->GetError().Clone();121return false;122}123124// Setting our type_sp to NULL will route everything back through our parent125// which is equivalent to not using dynamic values.126if (m_use_dynamic == lldb::eNoDynamicValues) {127m_dynamic_type_info.Clear();128return true;129}130131ExecutionContext exe_ctx(GetExecutionContextRef());132Target *target = exe_ctx.GetTargetPtr();133if (target) {134m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());135m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());136}137138// First make sure our Type and/or Address haven't changed:139Process *process = exe_ctx.GetProcessPtr();140if (!process)141return false;142143TypeAndOrName class_type_or_name;144Address dynamic_address;145bool found_dynamic_type = false;146Value::ValueType value_type;147llvm::ArrayRef<uint8_t> local_buffer;148149LanguageRuntime *runtime = nullptr;150151lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();152if (known_type != lldb::eLanguageTypeUnknown &&153known_type != lldb::eLanguageTypeC) {154runtime = process->GetLanguageRuntime(known_type);155if (auto *preferred_runtime =156runtime->GetPreferredLanguageRuntime(*m_parent)) {157// Try the preferred runtime first.158found_dynamic_type = preferred_runtime->GetDynamicTypeAndAddress(159*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,160value_type, local_buffer);161if (found_dynamic_type)162// Set the operative `runtime` for later use in this function.163runtime = preferred_runtime;164}165if (!found_dynamic_type)166// Fallback to the runtime for `known_type`.167found_dynamic_type = runtime->GetDynamicTypeAndAddress(168*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,169value_type, local_buffer);170} else {171runtime = process->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus);172if (runtime)173found_dynamic_type = runtime->GetDynamicTypeAndAddress(174*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,175value_type, local_buffer);176177if (!found_dynamic_type) {178runtime = process->GetLanguageRuntime(lldb::eLanguageTypeObjC);179if (runtime)180found_dynamic_type = runtime->GetDynamicTypeAndAddress(181*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,182value_type, local_buffer);183}184}185186// Getting the dynamic value may have run the program a bit, and so marked us187// as needing updating, but we really don't...188189m_update_point.SetUpdated();190191if (runtime && found_dynamic_type) {192if (class_type_or_name.HasType()) {193m_type_impl =194TypeImpl(m_parent->GetCompilerType(),195runtime->FixUpDynamicType(class_type_or_name, *m_parent)196.GetCompilerType());197} else {198m_type_impl.Clear();199}200} else {201m_type_impl.Clear();202}203204// If we don't have a dynamic type, set ourselves to be invalid and return205// false. We used to try to produce a dynamic ValueObject that behaved "like"206// its parent, but that failed for ValueObjectConstResult, which is too207// complex a beast to try to emulate. If we return an invalid ValueObject,208// clients will end up getting the static value instead, which behaves209// correctly.210if (!found_dynamic_type) {211if (m_dynamic_type_info)212SetValueDidChange(true);213ClearDynamicTypeInformation();214m_dynamic_type_info.Clear();215m_error = Status::FromErrorString("no dynamic type found");216return false;217}218219Value old_value(m_value);220221Log *log = GetLog(LLDBLog::Types);222223bool has_changed_type = false;224225if (!m_dynamic_type_info) {226m_dynamic_type_info = class_type_or_name;227has_changed_type = true;228} else if (class_type_or_name != m_dynamic_type_info) {229// We are another type, we need to tear down our children...230m_dynamic_type_info = class_type_or_name;231SetValueDidChange(true);232has_changed_type = true;233}234235if (has_changed_type)236ClearDynamicTypeInformation();237238if (!m_address.IsValid() || m_address != dynamic_address) {239if (m_address.IsValid())240SetValueDidChange(true);241242// If we found a host address, and the dynamic type fits in the local buffer243// that was found, point to that buffer. Later on this function will copy244// the buffer over.245if (value_type == Value::ValueType::HostAddress && !local_buffer.empty()) {246auto *exe_scope = exe_ctx.GetBestExecutionContextScope();247// If we found a host address but it doesn't fit in the buffer, there's248// nothing we can do.249if (local_buffer.size() <250llvm::expectedToOptional(251m_dynamic_type_info.GetCompilerType().GetByteSize(exe_scope))) {252SetValueIsValid(false);253return false;254}255256m_value.GetScalar() = (uint64_t)local_buffer.data();257m_address = LLDB_INVALID_ADDRESS;258} else {259// Otherwise we have a legitimate address on the target. Point to the load260// address.261m_address = dynamic_address;262lldb::TargetSP target_sp(GetTargetSP());263lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());264m_value.GetScalar() = load_address;265}266}267268if (runtime)269m_dynamic_type_info =270runtime->FixUpDynamicType(m_dynamic_type_info, *m_parent);271272m_value.SetCompilerType(m_dynamic_type_info.GetCompilerType());273274m_value.SetValueType(value_type);275276if (has_changed_type && log)277LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(),278static_cast<void *>(this), GetTypeName().GetCString());279280// m_address could be invalid but we could still have a local buffer281// containing the dynamic value.282if ((m_address.IsValid() ||283m_value.GetValueType() == Value::ValueType::HostAddress) &&284m_dynamic_type_info) {285// The variable value is in the Scalar value inside the m_value. We can286// point our m_data right to it.287m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());288if (m_error.Success()) {289if (!CanProvideValue()) {290// this value object represents an aggregate type whose children have291// values, but this object does not. So we say we are changed if our292// location has changed.293SetValueDidChange(m_value.GetValueType() != old_value.GetValueType() ||294m_value.GetScalar() != old_value.GetScalar());295}296297SetValueIsValid(true);298return true;299}300}301302// We get here if we've failed above...303SetValueIsValid(false);304return false;305}306307bool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); }308309bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str,310Status &error) {311if (!UpdateValueIfNeeded(false)) {312error = Status::FromErrorString("unable to read value");313return false;314}315316uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);317uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);318319if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {320error = Status::FromErrorString("unable to read value");321return false;322}323324// if we are at an offset from our parent, in order to set ourselves325// correctly we would need to change the new value so that it refers to the326// correct dynamic type. we choose not to deal with that - if anything more327// than a value overwrite is required, you should be using the expression328// parser instead of the value editing facility329if (my_value != parent_value) {330// but NULL'ing out a value should always be allowed331if (strcmp(value_str, "0")) {332error = Status::FromErrorString(333"unable to modify dynamic value, use 'expression' command");334return false;335}336}337338bool ret_val = m_parent->SetValueFromCString(value_str, error);339SetNeedsUpdate();340return ret_val;341}342343bool ValueObjectDynamicValue::SetData(DataExtractor &data, Status &error) {344if (!UpdateValueIfNeeded(false)) {345error = Status::FromErrorString("unable to read value");346return false;347}348349uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);350uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);351352if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {353error = Status::FromErrorString("unable to read value");354return false;355}356357// if we are at an offset from our parent, in order to set ourselves358// correctly we would need to change the new value so that it refers to the359// correct dynamic type. we choose not to deal with that - if anything more360// than a value overwrite is required, you should be using the expression361// parser instead of the value editing facility362if (my_value != parent_value) {363// but NULL'ing out a value should always be allowed364lldb::offset_t offset = 0;365366if (data.GetAddress(&offset) != 0) {367error = Status::FromErrorString(368"unable to modify dynamic value, use 'expression' command");369return false;370}371}372373bool ret_val = m_parent->SetData(data, error);374SetNeedsUpdate();375return ret_val;376}377378void ValueObjectDynamicValue::SetPreferredDisplayLanguage(379lldb::LanguageType lang) {380this->ValueObject::SetPreferredDisplayLanguage(lang);381if (m_parent)382m_parent->SetPreferredDisplayLanguage(lang);383}384385lldb::LanguageType ValueObjectDynamicValue::GetPreferredDisplayLanguage() {386if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {387if (m_parent)388return m_parent->GetPreferredDisplayLanguage();389return lldb::eLanguageTypeUnknown;390} else391return m_preferred_display_language;392}393394bool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() {395if (m_parent)396return m_parent->IsSyntheticChildrenGenerated();397return false;398}399400void ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b) {401if (m_parent)402m_parent->SetSyntheticChildrenGenerated(b);403this->ValueObject::SetSyntheticChildrenGenerated(b);404}405406bool ValueObjectDynamicValue::GetDeclaration(Declaration &decl) {407if (m_parent)408return m_parent->GetDeclaration(decl);409410return ValueObject::GetDeclaration(decl);411}412413uint64_t ValueObjectDynamicValue::GetLanguageFlags() {414if (m_parent)415return m_parent->GetLanguageFlags();416return this->ValueObject::GetLanguageFlags();417}418419void ValueObjectDynamicValue::SetLanguageFlags(uint64_t flags) {420if (m_parent)421m_parent->SetLanguageFlags(flags);422else423this->ValueObject::SetLanguageFlags(flags);424}425426427