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 | |