| //===-- ValueObjectChild.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/ValueObjectChild.h" |
| |
| #include "lldb/Core/Scalar.h" // for Scalar |
| #include "lldb/Core/Value.h" // for Value, Value::ValueType::e... |
| #include "lldb/Symbol/CompilerType.h" |
| #include "lldb/Target/ExecutionContext.h" |
| #include "lldb/Target/Process.h" |
| #include "lldb/Utility/Flags.h" // for Flags |
| #include "lldb/Utility/Status.h" // for Status |
| #include "lldb/lldb-forward.h" // for ProcessSP, ModuleSP |
| |
| #include <functional> // for _Func_impl<>::_Mybase |
| #include <memory> // for shared_ptr |
| #include <vector> // for vector |
| |
| #include <stdio.h> // for snprintf, size_t |
| #include <string.h> // for strlen |
| |
| using namespace lldb_private; |
| |
| ValueObjectChild::ValueObjectChild( |
| ValueObject &parent, const CompilerType &compiler_type, |
| const ConstString &name, uint64_t byte_size, int32_t byte_offset, |
| uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, |
| bool is_base_class, bool is_deref_of_parent, |
| AddressType child_ptr_or_ref_addr_type, uint64_t language_flags) |
| : ValueObject(parent), m_compiler_type(compiler_type), |
| m_byte_size(byte_size), m_byte_offset(byte_offset), |
| m_bitfield_bit_size(bitfield_bit_size), |
| m_bitfield_bit_offset(bitfield_bit_offset), |
| m_is_base_class(is_base_class), m_is_deref_of_parent(is_deref_of_parent), |
| m_can_update_with_invalid_exe_ctx() { |
| m_name = name; |
| SetAddressTypeOfChildren(child_ptr_or_ref_addr_type); |
| SetLanguageFlags(language_flags); |
| } |
| |
| ValueObjectChild::~ValueObjectChild() {} |
| |
| lldb::ValueType ValueObjectChild::GetValueType() const { |
| return m_parent->GetValueType(); |
| } |
| |
| size_t ValueObjectChild::CalculateNumChildren(uint32_t max) { |
| auto children_count = GetCompilerType().GetNumChildren(true); |
| return children_count <= max ? children_count : max; |
| } |
| |
| static void AdjustForBitfieldness(ConstString &name, |
| uint8_t bitfield_bit_size) { |
| if (name && bitfield_bit_size) { |
| const char *compiler_type_name = name.AsCString(); |
| if (compiler_type_name) { |
| std::vector<char> bitfield_type_name(strlen(compiler_type_name) + 32, 0); |
| ::snprintf(&bitfield_type_name.front(), bitfield_type_name.size(), |
| "%s:%u", compiler_type_name, bitfield_bit_size); |
| name.SetCString(&bitfield_type_name.front()); |
| } |
| } |
| } |
| |
| ConstString ValueObjectChild::GetTypeName() { |
| if (m_type_name.IsEmpty()) { |
| m_type_name = GetCompilerType().GetConstTypeName(); |
| AdjustForBitfieldness(m_type_name, m_bitfield_bit_size); |
| } |
| return m_type_name; |
| } |
| |
| ConstString ValueObjectChild::GetQualifiedTypeName() { |
| ConstString qualified_name = GetCompilerType().GetConstTypeName(); |
| AdjustForBitfieldness(qualified_name, m_bitfield_bit_size); |
| return qualified_name; |
| } |
| |
| ConstString ValueObjectChild::GetDisplayTypeName() { |
| ConstString display_name = GetCompilerType().GetDisplayTypeName(); |
| AdjustForBitfieldness(display_name, m_bitfield_bit_size); |
| return display_name; |
| } |
| |
| LazyBool ValueObjectChild::CanUpdateWithInvalidExecutionContext() { |
| if (m_can_update_with_invalid_exe_ctx.hasValue()) |
| return m_can_update_with_invalid_exe_ctx.getValue(); |
| if (m_parent) { |
| ValueObject *opinionated_parent = |
| m_parent->FollowParentChain([](ValueObject *valobj) -> bool { |
| return (valobj->CanUpdateWithInvalidExecutionContext() == |
| eLazyBoolCalculate); |
| }); |
| if (opinionated_parent) |
| return (m_can_update_with_invalid_exe_ctx = |
| opinionated_parent->CanUpdateWithInvalidExecutionContext()) |
| .getValue(); |
| } |
| return (m_can_update_with_invalid_exe_ctx = |
| this->ValueObject::CanUpdateWithInvalidExecutionContext()) |
| .getValue(); |
| } |
| |
| bool ValueObjectChild::UpdateValue() { |
| m_error.Clear(); |
| SetValueIsValid(false); |
| ValueObject *parent = m_parent; |
| if (parent) { |
| if (parent->UpdateValueIfNeeded(false)) { |
| m_value.SetCompilerType(GetCompilerType()); |
| |
| CompilerType parent_type(parent->GetCompilerType()); |
| // Copy the parent scalar value and the scalar value type |
| m_value.GetScalar() = parent->GetValue().GetScalar(); |
| Value::ValueType value_type = parent->GetValue().GetValueType(); |
| m_value.SetValueType(value_type); |
| |
| Flags parent_type_flags(parent_type.GetTypeInfo()); |
| const bool is_instance_ptr_base = |
| ((m_is_base_class == true) && |
| (parent_type_flags.AnySet(lldb::eTypeInstanceIsPointer))); |
| |
| if (parent->GetCompilerType().ShouldTreatScalarValueAsAddress()) { |
| lldb::addr_t addr = parent->GetPointerValue(); |
| m_value.GetScalar() = addr; |
| |
| if (addr == LLDB_INVALID_ADDRESS) { |
| m_error.SetErrorString("parent address is invalid."); |
| } else if (addr == 0) { |
| m_error.SetErrorString("parent is NULL"); |
| } else { |
| m_value.GetScalar() += m_byte_offset; |
| AddressType addr_type = parent->GetAddressTypeOfChildren(); |
| |
| switch (addr_type) { |
| case eAddressTypeFile: { |
| lldb::ProcessSP process_sp(GetProcessSP()); |
| if (process_sp && process_sp->IsAlive() == true) |
| m_value.SetValueType(Value::eValueTypeLoadAddress); |
| else |
| m_value.SetValueType(Value::eValueTypeFileAddress); |
| } break; |
| case eAddressTypeLoad: |
| m_value.SetValueType(is_instance_ptr_base |
| ? Value::eValueTypeScalar |
| : Value::eValueTypeLoadAddress); |
| break; |
| case eAddressTypeHost: |
| m_value.SetValueType(Value::eValueTypeHostAddress); |
| break; |
| case eAddressTypeInvalid: |
| // TODO: does this make sense? |
| m_value.SetValueType(Value::eValueTypeScalar); |
| break; |
| } |
| } |
| } else { |
| switch (value_type) { |
| case Value::eValueTypeLoadAddress: |
| case Value::eValueTypeFileAddress: |
| case Value::eValueTypeHostAddress: { |
| lldb::addr_t addr = |
| m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
| if (addr == LLDB_INVALID_ADDRESS) { |
| m_error.SetErrorString("parent address is invalid."); |
| } else if (addr == 0) { |
| m_error.SetErrorString("parent is NULL"); |
| } else { |
| // Set this object's scalar value to the address of its value by |
| // adding its byte offset to the parent address |
| m_value.GetScalar() += GetByteOffset(); |
| } |
| } break; |
| |
| case Value::eValueTypeScalar: |
| // try to extract the child value from the parent's scalar value |
| { |
| Scalar scalar(m_value.GetScalar()); |
| if (m_bitfield_bit_size) |
| scalar.ExtractBitfield(m_bitfield_bit_size, |
| m_bitfield_bit_offset); |
| else |
| scalar.ExtractBitfield(8 * m_byte_size, 8 * m_byte_offset); |
| m_value.GetScalar() = scalar; |
| } |
| break; |
| default: |
| m_error.SetErrorString("parent has invalid value."); |
| break; |
| } |
| } |
| |
| if (m_error.Success()) { |
| const bool thread_and_frame_only_if_stopped = true; |
| ExecutionContext exe_ctx( |
| GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped)); |
| if (GetCompilerType().GetTypeInfo() & lldb::eTypeHasValue) { |
| if (!is_instance_ptr_base) |
| m_error = |
| m_value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get()); |
| else |
| m_error = m_parent->GetValue().GetValueAsData(&exe_ctx, m_data, 0, |
| GetModule().get()); |
| } else { |
| m_error.Clear(); // No value so nothing to read... |
| } |
| } |
| |
| } else { |
| m_error.SetErrorStringWithFormat("parent failed to evaluate: %s", |
| parent->GetError().AsCString()); |
| } |
| } else { |
| m_error.SetErrorString("ValueObjectChild has a NULL parent ValueObject."); |
| } |
| |
| return m_error.Success(); |
| } |
| |
| bool ValueObjectChild::IsInScope() { |
| ValueObject *root(GetRoot()); |
| if (root) |
| return root->IsInScope(); |
| return false; |
| } |