| 1 | //===-- ValueObjectChild.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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "lldb/ValueObject/ValueObjectChild.h" |
| 10 | |
| 11 | #include "lldb/Core/Value.h" |
| 12 | #include "lldb/Symbol/CompilerType.h" |
| 13 | #include "lldb/Target/ExecutionContext.h" |
| 14 | #include "lldb/Target/Process.h" |
| 15 | #include "lldb/Utility/Flags.h" |
| 16 | #include "lldb/Utility/Scalar.h" |
| 17 | #include "lldb/Utility/Status.h" |
| 18 | #include "lldb/lldb-forward.h" |
| 19 | |
| 20 | #include <functional> |
| 21 | #include <memory> |
| 22 | #include <vector> |
| 23 | |
| 24 | #include <cstdio> |
| 25 | #include <cstring> |
| 26 | |
| 27 | using namespace lldb_private; |
| 28 | |
| 29 | ValueObjectChild::ValueObjectChild( |
| 30 | ValueObject &parent, const CompilerType &compiler_type, ConstString name, |
| 31 | uint64_t byte_size, int32_t byte_offset, uint32_t bitfield_bit_size, |
| 32 | uint32_t bitfield_bit_offset, bool is_base_class, bool is_deref_of_parent, |
| 33 | AddressType child_ptr_or_ref_addr_type, uint64_t language_flags) |
| 34 | : ValueObject(parent), m_compiler_type(compiler_type), |
| 35 | m_byte_size(byte_size), m_byte_offset(byte_offset), |
| 36 | m_bitfield_bit_size(bitfield_bit_size), |
| 37 | m_bitfield_bit_offset(bitfield_bit_offset), |
| 38 | m_is_base_class(is_base_class), m_is_deref_of_parent(is_deref_of_parent), |
| 39 | m_can_update_with_invalid_exe_ctx() { |
| 40 | m_name = name; |
| 41 | SetAddressTypeOfChildren(child_ptr_or_ref_addr_type); |
| 42 | SetLanguageFlags(language_flags); |
| 43 | } |
| 44 | |
| 45 | ValueObjectChild::~ValueObjectChild() = default; |
| 46 | |
| 47 | lldb::ValueType ValueObjectChild::GetValueType() const { |
| 48 | return m_parent->GetValueType(); |
| 49 | } |
| 50 | |
| 51 | llvm::Expected<uint32_t> ValueObjectChild::CalculateNumChildren(uint32_t max) { |
| 52 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
| 53 | auto children_count = GetCompilerType().GetNumChildren(omit_empty_base_classes: true, exe_ctx: &exe_ctx); |
| 54 | if (!children_count) |
| 55 | return children_count; |
| 56 | return *children_count <= max ? *children_count : max; |
| 57 | } |
| 58 | |
| 59 | static void AdjustForBitfieldness(ConstString &name, |
| 60 | uint8_t bitfield_bit_size) { |
| 61 | if (name && bitfield_bit_size) |
| 62 | name.SetString(llvm::formatv(Fmt: "{0}:{1}" , Vals&: name, Vals&: bitfield_bit_size).str()); |
| 63 | } |
| 64 | |
| 65 | ConstString ValueObjectChild::GetTypeName() { |
| 66 | if (m_type_name.IsEmpty()) { |
| 67 | m_type_name = GetCompilerType().GetTypeName(); |
| 68 | AdjustForBitfieldness(name&: m_type_name, bitfield_bit_size: m_bitfield_bit_size); |
| 69 | } |
| 70 | return m_type_name; |
| 71 | } |
| 72 | |
| 73 | ConstString ValueObjectChild::GetQualifiedTypeName() { |
| 74 | ConstString qualified_name = GetCompilerType().GetTypeName(); |
| 75 | AdjustForBitfieldness(name&: qualified_name, bitfield_bit_size: m_bitfield_bit_size); |
| 76 | return qualified_name; |
| 77 | } |
| 78 | |
| 79 | ConstString ValueObjectChild::GetDisplayTypeName() { |
| 80 | ConstString display_name = GetCompilerType().GetDisplayTypeName(); |
| 81 | AdjustForBitfieldness(name&: display_name, bitfield_bit_size: m_bitfield_bit_size); |
| 82 | return display_name; |
| 83 | } |
| 84 | |
| 85 | LazyBool ValueObjectChild::CanUpdateWithInvalidExecutionContext() { |
| 86 | if (m_can_update_with_invalid_exe_ctx) |
| 87 | return *m_can_update_with_invalid_exe_ctx; |
| 88 | if (m_parent) { |
| 89 | ValueObject *opinionated_parent = |
| 90 | m_parent->FollowParentChain([](ValueObject *valobj) -> bool { |
| 91 | return (valobj->CanUpdateWithInvalidExecutionContext() == |
| 92 | eLazyBoolCalculate); |
| 93 | }); |
| 94 | if (opinionated_parent) |
| 95 | return *(m_can_update_with_invalid_exe_ctx = |
| 96 | opinionated_parent->CanUpdateWithInvalidExecutionContext()); |
| 97 | } |
| 98 | return *(m_can_update_with_invalid_exe_ctx = |
| 99 | this->ValueObject::CanUpdateWithInvalidExecutionContext()); |
| 100 | } |
| 101 | |
| 102 | bool ValueObjectChild::UpdateValue() { |
| 103 | m_error.Clear(); |
| 104 | SetValueIsValid(false); |
| 105 | ValueObject *parent = m_parent; |
| 106 | if (parent) { |
| 107 | if (parent->UpdateValueIfNeeded(update_format: false)) { |
| 108 | m_value.SetCompilerType(GetCompilerType()); |
| 109 | |
| 110 | CompilerType parent_type(parent->GetCompilerType()); |
| 111 | // Copy the parent scalar value and the scalar value type |
| 112 | m_value.GetScalar() = parent->GetValue().GetScalar(); |
| 113 | m_value.SetValueType(parent->GetValue().GetValueType()); |
| 114 | |
| 115 | Flags parent_type_flags(parent_type.GetTypeInfo()); |
| 116 | const bool is_instance_ptr_base = |
| 117 | ((m_is_base_class) && |
| 118 | (parent_type_flags.AnySet(mask: lldb::eTypeInstanceIsPointer))); |
| 119 | |
| 120 | if (parent->GetCompilerType().ShouldTreatScalarValueAsAddress()) { |
| 121 | m_value.GetScalar() = parent->GetPointerValue().address; |
| 122 | |
| 123 | switch (parent->GetAddressTypeOfChildren()) { |
| 124 | case eAddressTypeFile: { |
| 125 | lldb::ProcessSP process_sp(GetProcessSP()); |
| 126 | if (process_sp && process_sp->IsAlive()) |
| 127 | m_value.SetValueType(Value::ValueType::LoadAddress); |
| 128 | else |
| 129 | m_value.SetValueType(Value::ValueType::FileAddress); |
| 130 | } break; |
| 131 | case eAddressTypeLoad: |
| 132 | m_value.SetValueType(is_instance_ptr_base |
| 133 | ? Value::ValueType::Scalar |
| 134 | : Value::ValueType::LoadAddress); |
| 135 | break; |
| 136 | case eAddressTypeHost: |
| 137 | m_value.SetValueType(Value::ValueType::HostAddress); |
| 138 | break; |
| 139 | case eAddressTypeInvalid: |
| 140 | // TODO: does this make sense? |
| 141 | m_value.SetValueType(Value::ValueType::Scalar); |
| 142 | break; |
| 143 | } |
| 144 | } |
| 145 | switch (m_value.GetValueType()) { |
| 146 | case Value::ValueType::Invalid: |
| 147 | break; |
| 148 | case Value::ValueType::LoadAddress: |
| 149 | case Value::ValueType::FileAddress: |
| 150 | case Value::ValueType::HostAddress: { |
| 151 | lldb::addr_t addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
| 152 | if (addr == LLDB_INVALID_ADDRESS) { |
| 153 | m_error = Status::FromErrorString(str: "parent address is invalid." ); |
| 154 | } else if (addr == 0) { |
| 155 | m_error = Status::FromErrorString(str: "parent is NULL" ); |
| 156 | } else { |
| 157 | // If a bitfield doesn't fit into the child_byte_size'd window at |
| 158 | // child_byte_offset, move the window forward until it fits. The |
| 159 | // problem here is that Value has no notion of bitfields and thus the |
| 160 | // Value's DataExtractor is sized like the bitfields CompilerType; a |
| 161 | // sequence of bitfields, however, can be larger than their underlying |
| 162 | // type. |
| 163 | if (m_bitfield_bit_offset) { |
| 164 | const bool thread_and_frame_only_if_stopped = true; |
| 165 | ExecutionContext exe_ctx(GetExecutionContextRef().Lock( |
| 166 | thread_and_frame_only_if_stopped)); |
| 167 | if (auto type_bit_size = |
| 168 | llvm::expectedToOptional(E: GetCompilerType().GetBitSize( |
| 169 | exe_scope: exe_ctx.GetBestExecutionContextScope()))) { |
| 170 | uint64_t bitfield_end = |
| 171 | m_bitfield_bit_size + m_bitfield_bit_offset; |
| 172 | if (bitfield_end > *type_bit_size) { |
| 173 | uint64_t overhang_bytes = |
| 174 | (bitfield_end - *type_bit_size + 7) / 8; |
| 175 | m_byte_offset += overhang_bytes; |
| 176 | m_bitfield_bit_offset -= overhang_bytes * 8; |
| 177 | } |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | // Set this object's scalar value to the address of its value by |
| 182 | // adding its byte offset to the parent address |
| 183 | m_value.GetScalar() += m_byte_offset; |
| 184 | } |
| 185 | } break; |
| 186 | |
| 187 | case Value::ValueType::Scalar: |
| 188 | // try to extract the child value from the parent's scalar value |
| 189 | { |
| 190 | Scalar scalar(m_value.GetScalar()); |
| 191 | scalar.ExtractBitfield(bit_size: 8 * m_byte_size, bit_offset: 8 * m_byte_offset); |
| 192 | m_value.GetScalar() = scalar; |
| 193 | } |
| 194 | break; |
| 195 | } |
| 196 | |
| 197 | if (m_error.Success()) { |
| 198 | const bool thread_and_frame_only_if_stopped = true; |
| 199 | ExecutionContext exe_ctx( |
| 200 | GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped)); |
| 201 | if (GetCompilerType().GetTypeInfo() & lldb::eTypeHasValue) { |
| 202 | Value &value = is_instance_ptr_base ? m_parent->GetValue() : m_value; |
| 203 | m_error = value.GetValueAsData(exe_ctx: &exe_ctx, data&: m_data, module: GetModule().get()); |
| 204 | } else { |
| 205 | m_error.Clear(); // No value so nothing to read... |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | } else { |
| 210 | m_error = Status::FromErrorStringWithFormat( |
| 211 | format: "parent failed to evaluate: %s" , parent->GetError().AsCString()); |
| 212 | } |
| 213 | } else { |
| 214 | m_error = Status::FromErrorString( |
| 215 | str: "ValueObjectChild has a NULL parent ValueObject." ); |
| 216 | } |
| 217 | |
| 218 | return m_error.Success(); |
| 219 | } |
| 220 | |
| 221 | bool ValueObjectChild::IsInScope() { |
| 222 | ValueObject *root(GetRoot()); |
| 223 | if (root) |
| 224 | return root->IsInScope(); |
| 225 | return false; |
| 226 | } |
| 227 | |