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