diff options
Diffstat (limited to 'source/Core/ValueObjectDynamicValue.cpp')
-rw-r--r-- | source/Core/ValueObjectDynamicValue.cpp | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp new file mode 100644 index 0000000..977cc4c --- /dev/null +++ b/source/Core/ValueObjectDynamicValue.cpp @@ -0,0 +1,372 @@ +//===-- ValueObjectDynamicValue.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "lldb/Core/ValueObjectDynamicValue.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ValueObjectList.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObject.h" + +#include "lldb/Symbol/ClangASTType.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/Variable.h" + +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + +using namespace lldb_private; + +ValueObjectDynamicValue::ValueObjectDynamicValue (ValueObject &parent, lldb::DynamicValueType use_dynamic) : + ValueObject(parent), + m_address (), + m_dynamic_type_info(), + m_use_dynamic (use_dynamic) +{ + SetName (parent.GetName()); +} + +ValueObjectDynamicValue::~ValueObjectDynamicValue() +{ + m_owning_valobj_sp.reset(); +} + +ClangASTType +ValueObjectDynamicValue::GetClangTypeImpl () +{ + if (m_dynamic_type_info.HasTypeSP()) + return m_value.GetClangType(); + else + return m_parent->GetClangType(); +} + +ConstString +ValueObjectDynamicValue::GetTypeName() +{ + const bool success = UpdateValueIfNeeded(false); + if (success) + { + if (m_dynamic_type_info.HasTypeSP()) + return GetClangType().GetConstTypeName(); + if (m_dynamic_type_info.HasName()) + return m_dynamic_type_info.GetName(); + } + return m_parent->GetTypeName(); +} + +ConstString +ValueObjectDynamicValue::GetQualifiedTypeName() +{ + const bool success = UpdateValueIfNeeded(false); + if (success) + { + if (m_dynamic_type_info.HasTypeSP()) + return GetClangType().GetConstQualifiedTypeName (); + if (m_dynamic_type_info.HasName()) + return m_dynamic_type_info.GetName(); + } + return m_parent->GetTypeName(); +} + +size_t +ValueObjectDynamicValue::CalculateNumChildren() +{ + const bool success = UpdateValueIfNeeded(false); + if (success && m_dynamic_type_info.HasTypeSP()) + return GetClangType().GetNumChildren (true); + else + return m_parent->GetNumChildren(); +} + +uint64_t +ValueObjectDynamicValue::GetByteSize() +{ + const bool success = UpdateValueIfNeeded(false); + if (success && m_dynamic_type_info.HasTypeSP()) + return m_value.GetValueByteSize(NULL); + else + return m_parent->GetByteSize(); +} + +lldb::ValueType +ValueObjectDynamicValue::GetValueType() const +{ + return m_parent->GetValueType(); +} + +bool +ValueObjectDynamicValue::UpdateValue () +{ + SetValueIsValid (false); + m_error.Clear(); + + if (!m_parent->UpdateValueIfNeeded(false)) + { + // The dynamic value failed to get an error, pass the error along + if (m_error.Success() && m_parent->GetError().Fail()) + m_error = m_parent->GetError(); + return false; + } + + // Setting our type_sp to NULL will route everything back through our + // parent which is equivalent to not using dynamic values. + if (m_use_dynamic == lldb::eNoDynamicValues) + { + m_dynamic_type_info.Clear(); + return true; + } + + ExecutionContext exe_ctx (GetExecutionContextRef()); + Target *target = exe_ctx.GetTargetPtr(); + if (target) + { + m_data.SetByteOrder(target->GetArchitecture().GetByteOrder()); + m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); + } + + // First make sure our Type and/or Address haven't changed: + Process *process = exe_ctx.GetProcessPtr(); + if (!process) + return false; + + TypeAndOrName class_type_or_name; + Address dynamic_address; + bool found_dynamic_type = false; + + lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage(); + if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC) + { + LanguageRuntime *runtime = process->GetLanguageRuntime (known_type); + if (runtime) + found_dynamic_type = runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); + } + else + { + LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus); + if (cpp_runtime) + found_dynamic_type = cpp_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); + + if (!found_dynamic_type) + { + LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC); + if (objc_runtime) + found_dynamic_type = objc_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); + } + } + + // Getting the dynamic value may have run the program a bit, and so marked us as needing updating, but we really + // don't... + + m_update_point.SetUpdated(); + + // If we don't have a dynamic type, then make ourselves just a echo of our parent. + // Or we could return false, and make ourselves an echo of our parent? + if (!found_dynamic_type) + { + if (m_dynamic_type_info) + SetValueDidChange(true); + ClearDynamicTypeInformation(); + m_dynamic_type_info.Clear(); + m_value = m_parent->GetValue(); + m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get()); + return m_error.Success(); + } + + Value old_value(m_value); + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + + bool has_changed_type = false; + + if (!m_dynamic_type_info) + { + m_dynamic_type_info = class_type_or_name; + has_changed_type = true; + } + else if (class_type_or_name != m_dynamic_type_info) + { + // We are another type, we need to tear down our children... + m_dynamic_type_info = class_type_or_name; + SetValueDidChange (true); + has_changed_type = true; + } + + if (has_changed_type) + ClearDynamicTypeInformation (); + + if (!m_address.IsValid() || m_address != dynamic_address) + { + if (m_address.IsValid()) + SetValueDidChange (true); + + // We've moved, so we should be fine... + m_address = dynamic_address; + lldb::TargetSP target_sp (GetTargetSP()); + lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get()); + m_value.GetScalar() = load_address; + } + + ClangASTType corrected_type; + if (m_dynamic_type_info.HasTypeSP()) + { + // The type will always be the type of the dynamic object. If our parent's type was a pointer, + // then our type should be a pointer to the type of the dynamic object. If a reference, then the original type + // should be okay... + ClangASTType orig_type = m_dynamic_type_info.GetTypeSP()->GetClangForwardType(); + corrected_type = orig_type; + if (m_parent->IsPointerType()) + corrected_type = orig_type.GetPointerType (); + else if (m_parent->IsPointerOrReferenceType()) + corrected_type = orig_type.GetLValueReferenceType (); + } + else /*if (m_dynamic_type_info.HasName())*/ + { + // If we are here we need to adjust our dynamic type name to include the correct & or * symbol + std::string type_name_buf (m_dynamic_type_info.GetName().GetCString()); + if (m_parent->IsPointerType()) + type_name_buf.append(" *"); + else if (m_parent->IsPointerOrReferenceType()) + type_name_buf.append(" &"); + corrected_type = m_parent->GetClangType(); + m_dynamic_type_info.SetName(type_name_buf.c_str()); + } + + //m_value.SetContext (Value::eContextTypeClangType, corrected_type); + m_value.SetClangType (corrected_type); + + // Our address is the location of the dynamic type stored in memory. It isn't a load address, + // because we aren't pointing to the LOCATION that stores the pointer to us, we're pointing to us... + m_value.SetValueType(Value::eValueTypeScalar); + + if (has_changed_type && log) + log->Printf("[%s %p] has a new dynamic type %s", + GetName().GetCString(), + this, + GetTypeName().GetCString()); + + if (m_address.IsValid() && m_dynamic_type_info) + { + // The variable value is in the Scalar value inside the m_value. + // We can point our m_data right to it. + m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get()); + if (m_error.Success()) + { + if (GetClangType().IsAggregateType ()) + { + // this value object represents an aggregate type whose + // children have values, but this object does not. So we + // say we are changed if our location has changed. + SetValueDidChange (m_value.GetValueType() != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar()); + } + + SetValueIsValid (true); + return true; + } + } + + // We get here if we've failed above... + SetValueIsValid (false); + return false; +} + + + +bool +ValueObjectDynamicValue::IsInScope () +{ + return m_parent->IsInScope(); +} + +bool +ValueObjectDynamicValue::SetValueFromCString (const char *value_str, Error& error) +{ + if (!UpdateValueIfNeeded(false)) + { + error.SetErrorString("unable to read value"); + return false; + } + + uint64_t my_value = GetValueAsUnsigned(UINT64_MAX); + uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX); + + if (my_value == UINT64_MAX || parent_value == UINT64_MAX) + { + error.SetErrorString("unable to read value"); + return false; + } + + // if we are at an offset from our parent, in order to set ourselves correctly we would need + // to change the new value so that it refers to the correct dynamic type. we choose not to deal + // with that - if anything more than a value overwrite is required, you should be using the + // expression parser instead of the value editing facility + if (my_value != parent_value) + { + // but NULL'ing out a value should always be allowed + if (strcmp(value_str,"0")) + { + error.SetErrorString("unable to modify dynamic value, use 'expression' command"); + return false; + } + } + + bool ret_val = m_parent->SetValueFromCString(value_str,error); + SetNeedsUpdate(); + return ret_val; +} + +bool +ValueObjectDynamicValue::SetData (DataExtractor &data, Error &error) +{ + if (!UpdateValueIfNeeded(false)) + { + error.SetErrorString("unable to read value"); + return false; + } + + uint64_t my_value = GetValueAsUnsigned(UINT64_MAX); + uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX); + + if (my_value == UINT64_MAX || parent_value == UINT64_MAX) + { + error.SetErrorString("unable to read value"); + return false; + } + + // if we are at an offset from our parent, in order to set ourselves correctly we would need + // to change the new value so that it refers to the correct dynamic type. we choose not to deal + // with that - if anything more than a value overwrite is required, you should be using the + // expression parser instead of the value editing facility + if (my_value != parent_value) + { + // but NULL'ing out a value should always be allowed + lldb::offset_t offset = 0; + + if (data.GetPointer(&offset) != 0) + { + error.SetErrorString("unable to modify dynamic value, use 'expression' command"); + return false; + } + } + + bool ret_val = m_parent->SetData(data, error); + SetNeedsUpdate(); + return ret_val; +} |