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