Path: blob/main/contrib/llvm-project/lldb/source/Core/ValueObjectDynamicValue.cpp
39587 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/Core/ValueObjectDynamicValue.h"9#include "lldb/Core/Value.h"10#include "lldb/Core/ValueObject.h"11#include "lldb/Symbol/CompilerType.h"12#include "lldb/Symbol/Type.h"13#include "lldb/Target/ExecutionContext.h"14#include "lldb/Target/LanguageRuntime.h"15#include "lldb/Target/Process.h"16#include "lldb/Target/Target.h"17#include "lldb/Utility/DataExtractor.h"18#include "lldb/Utility/LLDBLog.h"19#include "lldb/Utility/Log.h"20#include "lldb/Utility/Scalar.h"21#include "lldb/Utility/Status.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}99100std::optional<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();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;147148LanguageRuntime *runtime = nullptr;149150lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();151if (known_type != lldb::eLanguageTypeUnknown &&152known_type != lldb::eLanguageTypeC) {153runtime = process->GetLanguageRuntime(known_type);154if (auto *preferred_runtime =155runtime->GetPreferredLanguageRuntime(*m_parent)) {156// Try the preferred runtime first.157found_dynamic_type = preferred_runtime->GetDynamicTypeAndAddress(158*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,159value_type);160if (found_dynamic_type)161// Set the operative `runtime` for later use in this function.162runtime = preferred_runtime;163}164if (!found_dynamic_type)165// Fallback to the runtime for `known_type`.166found_dynamic_type = runtime->GetDynamicTypeAndAddress(167*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,168value_type);169} else {170runtime = process->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus);171if (runtime)172found_dynamic_type = runtime->GetDynamicTypeAndAddress(173*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,174value_type);175176if (!found_dynamic_type) {177runtime = process->GetLanguageRuntime(lldb::eLanguageTypeObjC);178if (runtime)179found_dynamic_type = runtime->GetDynamicTypeAndAddress(180*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,181value_type);182}183}184185// Getting the dynamic value may have run the program a bit, and so marked us186// as needing updating, but we really don't...187188m_update_point.SetUpdated();189190if (runtime && found_dynamic_type) {191if (class_type_or_name.HasType()) {192m_type_impl =193TypeImpl(m_parent->GetCompilerType(),194runtime->FixUpDynamicType(class_type_or_name, *m_parent)195.GetCompilerType());196} else {197m_type_impl.Clear();198}199} else {200m_type_impl.Clear();201}202203// If we don't have a dynamic type, set ourselves to be invalid and return204// false. We used to try to produce a dynamic ValueObject that behaved "like"205// its parent, but that failed for ValueObjectConstResult, which is too206// complex a beast to try to emulate. If we return an invalid ValueObject,207// clients will end up getting the static value instead, which behaves208// correctly.209if (!found_dynamic_type) {210if (m_dynamic_type_info)211SetValueDidChange(true);212ClearDynamicTypeInformation();213m_dynamic_type_info.Clear();214m_error.SetErrorString("no dynamic type found");215return false;216}217218Value old_value(m_value);219220Log *log = GetLog(LLDBLog::Types);221222bool has_changed_type = false;223224if (!m_dynamic_type_info) {225m_dynamic_type_info = class_type_or_name;226has_changed_type = true;227} else if (class_type_or_name != m_dynamic_type_info) {228// We are another type, we need to tear down our children...229m_dynamic_type_info = class_type_or_name;230SetValueDidChange(true);231has_changed_type = true;232}233234if (has_changed_type)235ClearDynamicTypeInformation();236237if (!m_address.IsValid() || m_address != dynamic_address) {238if (m_address.IsValid())239SetValueDidChange(true);240241// We've moved, so we should be fine...242m_address = dynamic_address;243lldb::TargetSP target_sp(GetTargetSP());244lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());245m_value.GetScalar() = load_address;246}247248if (runtime)249m_dynamic_type_info =250runtime->FixUpDynamicType(m_dynamic_type_info, *m_parent);251252m_value.SetCompilerType(m_dynamic_type_info.GetCompilerType());253254m_value.SetValueType(value_type);255256if (has_changed_type && log)257LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(),258static_cast<void *>(this), GetTypeName().GetCString());259260if (m_address.IsValid() && m_dynamic_type_info) {261// The variable value is in the Scalar value inside the m_value. We can262// point our m_data right to it.263m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());264if (m_error.Success()) {265if (!CanProvideValue()) {266// this value object represents an aggregate type whose children have267// values, but this object does not. So we say we are changed if our268// location has changed.269SetValueDidChange(m_value.GetValueType() != old_value.GetValueType() ||270m_value.GetScalar() != old_value.GetScalar());271}272273SetValueIsValid(true);274return true;275}276}277278// We get here if we've failed above...279SetValueIsValid(false);280return false;281}282283bool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); }284285bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str,286Status &error) {287if (!UpdateValueIfNeeded(false)) {288error.SetErrorString("unable to read value");289return false;290}291292uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);293uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);294295if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {296error.SetErrorString("unable to read value");297return false;298}299300// if we are at an offset from our parent, in order to set ourselves301// correctly we would need to change the new value so that it refers to the302// correct dynamic type. we choose not to deal with that - if anything more303// than a value overwrite is required, you should be using the expression304// parser instead of the value editing facility305if (my_value != parent_value) {306// but NULL'ing out a value should always be allowed307if (strcmp(value_str, "0")) {308error.SetErrorString(309"unable to modify dynamic value, use 'expression' command");310return false;311}312}313314bool ret_val = m_parent->SetValueFromCString(value_str, error);315SetNeedsUpdate();316return ret_val;317}318319bool ValueObjectDynamicValue::SetData(DataExtractor &data, Status &error) {320if (!UpdateValueIfNeeded(false)) {321error.SetErrorString("unable to read value");322return false;323}324325uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);326uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);327328if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {329error.SetErrorString("unable to read value");330return false;331}332333// if we are at an offset from our parent, in order to set ourselves334// correctly we would need to change the new value so that it refers to the335// correct dynamic type. we choose not to deal with that - if anything more336// than a value overwrite is required, you should be using the expression337// parser instead of the value editing facility338if (my_value != parent_value) {339// but NULL'ing out a value should always be allowed340lldb::offset_t offset = 0;341342if (data.GetAddress(&offset) != 0) {343error.SetErrorString(344"unable to modify dynamic value, use 'expression' command");345return false;346}347}348349bool ret_val = m_parent->SetData(data, error);350SetNeedsUpdate();351return ret_val;352}353354void ValueObjectDynamicValue::SetPreferredDisplayLanguage(355lldb::LanguageType lang) {356this->ValueObject::SetPreferredDisplayLanguage(lang);357if (m_parent)358m_parent->SetPreferredDisplayLanguage(lang);359}360361lldb::LanguageType ValueObjectDynamicValue::GetPreferredDisplayLanguage() {362if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {363if (m_parent)364return m_parent->GetPreferredDisplayLanguage();365return lldb::eLanguageTypeUnknown;366} else367return m_preferred_display_language;368}369370bool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() {371if (m_parent)372return m_parent->IsSyntheticChildrenGenerated();373return false;374}375376void ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b) {377if (m_parent)378m_parent->SetSyntheticChildrenGenerated(b);379this->ValueObject::SetSyntheticChildrenGenerated(b);380}381382bool ValueObjectDynamicValue::GetDeclaration(Declaration &decl) {383if (m_parent)384return m_parent->GetDeclaration(decl);385386return ValueObject::GetDeclaration(decl);387}388389uint64_t ValueObjectDynamicValue::GetLanguageFlags() {390if (m_parent)391return m_parent->GetLanguageFlags();392return this->ValueObject::GetLanguageFlags();393}394395void ValueObjectDynamicValue::SetLanguageFlags(uint64_t flags) {396if (m_parent)397m_parent->SetLanguageFlags(flags);398else399this->ValueObject::SetLanguageFlags(flags);400}401402403