brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.1 KiB · 4c2cf07 Raw
426 lines · cpp
1//===-- ValueObjectDynamicValue.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/ValueObjectDynamicValue.h"10#include "lldb/Core/Value.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/ValueObject/ValueObject.h"23#include "lldb/lldb-types.h"24 25#include <cstring>26#include <optional>27namespace lldb_private {28class Declaration;29}30 31using namespace lldb_private;32 33ValueObjectDynamicValue::ValueObjectDynamicValue(34    ValueObject &parent, lldb::DynamicValueType use_dynamic)35    : ValueObject(parent), m_address(), m_dynamic_type_info(),36      m_use_dynamic(use_dynamic) {37  SetName(parent.GetName());38}39 40CompilerType ValueObjectDynamicValue::GetCompilerTypeImpl() {41  const bool success = UpdateValueIfNeeded(false);42  if (success) {43    if (m_dynamic_type_info.HasType())44      return m_value.GetCompilerType();45    else46      return m_parent->GetCompilerType();47  }48  return m_parent->GetCompilerType();49}50 51ConstString ValueObjectDynamicValue::GetTypeName() {52  const bool success = UpdateValueIfNeeded(false);53  if (success) {54    if (m_dynamic_type_info.HasName())55      return m_dynamic_type_info.GetName();56  }57  return m_parent->GetTypeName();58}59 60TypeImpl ValueObjectDynamicValue::GetTypeImpl() {61  const bool success = UpdateValueIfNeeded(false);62  if (success && m_type_impl.IsValid()) {63    return m_type_impl;64  }65  return m_parent->GetTypeImpl();66}67 68ConstString ValueObjectDynamicValue::GetQualifiedTypeName() {69  const bool success = UpdateValueIfNeeded(false);70  if (success) {71    if (m_dynamic_type_info.HasName())72      return m_dynamic_type_info.GetName();73  }74  return m_parent->GetQualifiedTypeName();75}76 77ConstString ValueObjectDynamicValue::GetDisplayTypeName() {78  const bool success = UpdateValueIfNeeded(false);79  if (success) {80    if (m_dynamic_type_info.HasType())81      return GetCompilerType().GetDisplayTypeName();82    if (m_dynamic_type_info.HasName())83      return m_dynamic_type_info.GetName();84  }85  return m_parent->GetDisplayTypeName();86}87 88llvm::Expected<uint32_t>89ValueObjectDynamicValue::CalculateNumChildren(uint32_t max) {90  const bool success = UpdateValueIfNeeded(false);91  if (success && m_dynamic_type_info.HasType()) {92    ExecutionContext exe_ctx(GetExecutionContextRef());93    auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx);94    if (!children_count)95      return children_count;96    return *children_count <= max ? *children_count : max;97  } else98    return m_parent->GetNumChildren(max);99}100 101llvm::Expected<uint64_t> ValueObjectDynamicValue::GetByteSize() {102  const bool success = UpdateValueIfNeeded(false);103  if (success && m_dynamic_type_info.HasType()) {104    ExecutionContext exe_ctx(GetExecutionContextRef());105    return m_value.GetValueByteSize(nullptr, &exe_ctx);106  } else107    return m_parent->GetByteSize();108}109 110lldb::ValueType ValueObjectDynamicValue::GetValueType() const {111  return m_parent->GetValueType();112}113 114bool ValueObjectDynamicValue::UpdateValue() {115  SetValueIsValid(false);116  m_error.Clear();117 118  if (!m_parent->UpdateValueIfNeeded(false)) {119    // The dynamic value failed to get an error, pass the error along120    if (m_error.Success() && m_parent->GetError().Fail())121      m_error = m_parent->GetError().Clone();122    return false;123  }124 125  // Setting our type_sp to NULL will route everything back through our parent126  // which is equivalent to not using dynamic values.127  if (m_use_dynamic == lldb::eNoDynamicValues) {128    m_dynamic_type_info.Clear();129    return true;130  }131 132  ExecutionContext exe_ctx(GetExecutionContextRef());133  Target *target = exe_ctx.GetTargetPtr();134  if (target) {135    m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());136    m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());137  }138 139  // First make sure our Type and/or Address haven't changed:140  Process *process = exe_ctx.GetProcessPtr();141  if (!process)142    return false;143 144  TypeAndOrName class_type_or_name;145  Address dynamic_address;146  bool found_dynamic_type = false;147  Value::ValueType value_type;148  llvm::ArrayRef<uint8_t> local_buffer;149 150  LanguageRuntime *runtime = nullptr;151 152  lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();153  if (known_type != lldb::eLanguageTypeUnknown &&154      known_type != lldb::eLanguageTypeC) {155    runtime = process->GetLanguageRuntime(known_type);156    if (auto *preferred_runtime =157            runtime->GetPreferredLanguageRuntime(*m_parent)) {158      // Try the preferred runtime first.159      found_dynamic_type = preferred_runtime->GetDynamicTypeAndAddress(160          *m_parent, m_use_dynamic, class_type_or_name, dynamic_address,161          value_type, local_buffer);162      if (found_dynamic_type)163        // Set the operative `runtime` for later use in this function.164        runtime = preferred_runtime;165    }166    if (!found_dynamic_type)167      // Fallback to the runtime for `known_type`.168      found_dynamic_type = runtime->GetDynamicTypeAndAddress(169          *m_parent, m_use_dynamic, class_type_or_name, dynamic_address,170          value_type, local_buffer);171  } else {172    runtime = process->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus);173    if (runtime)174      found_dynamic_type = runtime->GetDynamicTypeAndAddress(175          *m_parent, m_use_dynamic, class_type_or_name, dynamic_address,176          value_type, local_buffer);177 178    if (!found_dynamic_type) {179      runtime = process->GetLanguageRuntime(lldb::eLanguageTypeObjC);180      if (runtime)181        found_dynamic_type = runtime->GetDynamicTypeAndAddress(182            *m_parent, m_use_dynamic, class_type_or_name, dynamic_address,183            value_type, local_buffer);184    }185  }186 187  // Getting the dynamic value may have run the program a bit, and so marked us188  // as needing updating, but we really don't...189 190  m_update_point.SetUpdated();191 192  if (runtime && found_dynamic_type) {193    if (class_type_or_name.HasType()) {194      m_type_impl =195          TypeImpl(m_parent->GetCompilerType(),196                   runtime->FixUpDynamicType(class_type_or_name, *m_parent)197                       .GetCompilerType());198    } else {199      m_type_impl.Clear();200    }201  } else {202    m_type_impl.Clear();203  }204 205  // If we don't have a dynamic type, set ourselves to be invalid and return206  // false.  We used to try to produce a dynamic ValueObject that behaved "like"207  // its parent, but that failed for ValueObjectConstResult, which is too208  // complex a beast to try to emulate.  If we return an invalid ValueObject,209  // clients will end up getting the static value instead, which behaves210  // correctly.211  if (!found_dynamic_type) {212    if (m_dynamic_type_info)213      SetValueDidChange(true);214    ClearDynamicTypeInformation();215    m_dynamic_type_info.Clear();216    m_error = Status::FromErrorString("no dynamic type found");217    return false;218  }219 220  Value old_value(m_value);221 222  Log *log = GetLog(LLDBLog::Types);223 224  bool has_changed_type = false;225 226  if (!m_dynamic_type_info) {227    m_dynamic_type_info = class_type_or_name;228    has_changed_type = true;229  } else if (class_type_or_name != m_dynamic_type_info) {230    // We are another type, we need to tear down our children...231    m_dynamic_type_info = class_type_or_name;232    SetValueDidChange(true);233    has_changed_type = true;234  }235 236  if (has_changed_type)237    ClearDynamicTypeInformation();238 239  if (!m_address.IsValid() || m_address != dynamic_address) {240    if (m_address.IsValid())241      SetValueDidChange(true);242 243    // If we found a host address, and the dynamic type fits in the local buffer244    // that was found, point to that buffer. Later on this function will copy245    // the buffer over.246    if (value_type == Value::ValueType::HostAddress && !local_buffer.empty()) {247      auto *exe_scope = exe_ctx.GetBestExecutionContextScope();248      // If we found a host address but it doesn't fit in the buffer, there's249      // nothing we can do.250      if (local_buffer.size() <251          llvm::expectedToOptional(252              m_dynamic_type_info.GetCompilerType().GetByteSize(exe_scope))) {253        SetValueIsValid(false);254        return false;255      }256 257      m_value.GetScalar() = (uint64_t)local_buffer.data();258      m_address = LLDB_INVALID_ADDRESS;259    } else {260      // Otherwise we have a legitimate address on the target. Point to the load261      // address.262      m_address = dynamic_address;263      lldb::TargetSP target_sp(GetTargetSP());264      lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());265      m_value.GetScalar() = load_address;266    }267  }268 269  if (runtime)270    m_dynamic_type_info =271        runtime->FixUpDynamicType(m_dynamic_type_info, *m_parent);272 273  m_value.SetCompilerType(m_dynamic_type_info.GetCompilerType());274 275  m_value.SetValueType(value_type);276 277  if (has_changed_type && log)278    LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(),279              static_cast<void *>(this), GetTypeName().GetCString());280 281  // m_address could be invalid but we could still have a local buffer282  // containing the dynamic value.283  if ((m_address.IsValid() ||284       m_value.GetValueType() == Value::ValueType::HostAddress) &&285      m_dynamic_type_info) {286    // The variable value is in the Scalar value inside the m_value. We can287    // point our m_data right to it.288    m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());289    if (m_error.Success()) {290      if (!CanProvideValue()) {291        // this value object represents an aggregate type whose children have292        // values, but this object does not. So we say we are changed if our293        // location has changed.294        SetValueDidChange(m_value.GetValueType() != old_value.GetValueType() ||295                          m_value.GetScalar() != old_value.GetScalar());296      }297 298      SetValueIsValid(true);299      return true;300    }301  }302 303  // We get here if we've failed above...304  SetValueIsValid(false);305  return false;306}307 308bool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); }309 310bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str,311                                                  Status &error) {312  if (!UpdateValueIfNeeded(false)) {313    error = Status::FromErrorString("unable to read value");314    return false;315  }316 317  uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);318  uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);319 320  if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {321    error = Status::FromErrorString("unable to read value");322    return false;323  }324 325  // if we are at an offset from our parent, in order to set ourselves326  // correctly we would need to change the new value so that it refers to the327  // correct dynamic type. we choose not to deal with that - if anything more328  // than a value overwrite is required, you should be using the expression329  // parser instead of the value editing facility330  if (my_value != parent_value) {331    // but NULL'ing out a value should always be allowed332    if (strcmp(value_str, "0")) {333      error = Status::FromErrorString(334          "unable to modify dynamic value, use 'expression' command");335      return false;336    }337  }338 339  bool ret_val = m_parent->SetValueFromCString(value_str, error);340  SetNeedsUpdate();341  return ret_val;342}343 344bool ValueObjectDynamicValue::SetData(DataExtractor &data, Status &error) {345  if (!UpdateValueIfNeeded(false)) {346    error = Status::FromErrorString("unable to read value");347    return false;348  }349 350  uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);351  uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);352 353  if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {354    error = Status::FromErrorString("unable to read value");355    return false;356  }357 358  // if we are at an offset from our parent, in order to set ourselves359  // correctly we would need to change the new value so that it refers to the360  // correct dynamic type. we choose not to deal with that - if anything more361  // than a value overwrite is required, you should be using the expression362  // parser instead of the value editing facility363  if (my_value != parent_value) {364    // but NULL'ing out a value should always be allowed365    lldb::offset_t offset = 0;366 367    if (data.GetAddress(&offset) != 0) {368      error = Status::FromErrorString(369          "unable to modify dynamic value, use 'expression' command");370      return false;371    }372  }373 374  bool ret_val = m_parent->SetData(data, error);375  SetNeedsUpdate();376  return ret_val;377}378 379void ValueObjectDynamicValue::SetPreferredDisplayLanguage(380    lldb::LanguageType lang) {381  this->ValueObject::SetPreferredDisplayLanguage(lang);382  if (m_parent)383    m_parent->SetPreferredDisplayLanguage(lang);384}385 386lldb::LanguageType ValueObjectDynamicValue::GetPreferredDisplayLanguage() {387  if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {388    if (m_parent)389      return m_parent->GetPreferredDisplayLanguage();390    return lldb::eLanguageTypeUnknown;391  } else392    return m_preferred_display_language;393}394 395bool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() {396  if (m_parent)397    return m_parent->IsSyntheticChildrenGenerated();398  return false;399}400 401void ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b) {402  if (m_parent)403    m_parent->SetSyntheticChildrenGenerated(b);404  this->ValueObject::SetSyntheticChildrenGenerated(b);405}406 407bool ValueObjectDynamicValue::GetDeclaration(Declaration &decl) {408  if (m_parent)409    return m_parent->GetDeclaration(decl);410 411  return ValueObject::GetDeclaration(decl);412}413 414uint64_t ValueObjectDynamicValue::GetLanguageFlags() {415  if (m_parent)416    return m_parent->GetLanguageFlags();417  return this->ValueObject::GetLanguageFlags();418}419 420void ValueObjectDynamicValue::SetLanguageFlags(uint64_t flags) {421  if (m_parent)422    m_parent->SetLanguageFlags(flags);423  else424    this->ValueObject::SetLanguageFlags(flags);425}426