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 | llvm::Expected<uint32_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 | if (!children_count) |
56 | return children_count; |
57 | return *children_count <= max ? *children_count : max; |
58 | } |
59 | |
60 | static void AdjustForBitfieldness(ConstString &name, |
61 | uint8_t bitfield_bit_size) { |
62 | if (name && bitfield_bit_size) |
63 | name.SetString(llvm::formatv(Fmt: "{0}:{1}" , Vals&: name, Vals&: bitfield_bit_size).str()); |
64 | } |
65 | |
66 | ConstString ValueObjectChild::GetTypeName() { |
67 | if (m_type_name.IsEmpty()) { |
68 | m_type_name = GetCompilerType().GetTypeName(); |
69 | AdjustForBitfieldness(name&: m_type_name, bitfield_bit_size: m_bitfield_bit_size); |
70 | } |
71 | return m_type_name; |
72 | } |
73 | |
74 | ConstString ValueObjectChild::GetQualifiedTypeName() { |
75 | ConstString qualified_name = GetCompilerType().GetTypeName(); |
76 | AdjustForBitfieldness(name&: qualified_name, bitfield_bit_size: m_bitfield_bit_size); |
77 | return qualified_name; |
78 | } |
79 | |
80 | ConstString ValueObjectChild::GetDisplayTypeName() { |
81 | ConstString display_name = GetCompilerType().GetDisplayTypeName(); |
82 | AdjustForBitfieldness(name&: display_name, bitfield_bit_size: m_bitfield_bit_size); |
83 | return display_name; |
84 | } |
85 | |
86 | LazyBool ValueObjectChild::CanUpdateWithInvalidExecutionContext() { |
87 | if (m_can_update_with_invalid_exe_ctx) |
88 | return *m_can_update_with_invalid_exe_ctx; |
89 | if (m_parent) { |
90 | ValueObject *opinionated_parent = |
91 | m_parent->FollowParentChain([](ValueObject *valobj) -> bool { |
92 | return (valobj->CanUpdateWithInvalidExecutionContext() == |
93 | eLazyBoolCalculate); |
94 | }); |
95 | if (opinionated_parent) |
96 | return *(m_can_update_with_invalid_exe_ctx = |
97 | opinionated_parent->CanUpdateWithInvalidExecutionContext()); |
98 | } |
99 | return *(m_can_update_with_invalid_exe_ctx = |
100 | this->ValueObject::CanUpdateWithInvalidExecutionContext()); |
101 | } |
102 | |
103 | bool ValueObjectChild::UpdateValue() { |
104 | m_error.Clear(); |
105 | SetValueIsValid(false); |
106 | ValueObject *parent = m_parent; |
107 | if (parent) { |
108 | if (parent->UpdateValueIfNeeded(update_format: false)) { |
109 | m_value.SetCompilerType(GetCompilerType()); |
110 | |
111 | CompilerType parent_type(parent->GetCompilerType()); |
112 | // Copy the parent scalar value and the scalar value type |
113 | m_value.GetScalar() = parent->GetValue().GetScalar(); |
114 | m_value.SetValueType(parent->GetValue().GetValueType()); |
115 | |
116 | Flags parent_type_flags(parent_type.GetTypeInfo()); |
117 | const bool is_instance_ptr_base = |
118 | ((m_is_base_class) && |
119 | (parent_type_flags.AnySet(mask: lldb::eTypeInstanceIsPointer))); |
120 | |
121 | if (parent->GetCompilerType().ShouldTreatScalarValueAsAddress()) { |
122 | m_value.GetScalar() = parent->GetPointerValue(); |
123 | |
124 | switch (parent->GetAddressTypeOfChildren()) { |
125 | case eAddressTypeFile: { |
126 | lldb::ProcessSP process_sp(GetProcessSP()); |
127 | if (process_sp && process_sp->IsAlive()) |
128 | m_value.SetValueType(Value::ValueType::LoadAddress); |
129 | else |
130 | m_value.SetValueType(Value::ValueType::FileAddress); |
131 | } break; |
132 | case eAddressTypeLoad: |
133 | m_value.SetValueType(is_instance_ptr_base |
134 | ? Value::ValueType::Scalar |
135 | : Value::ValueType::LoadAddress); |
136 | break; |
137 | case eAddressTypeHost: |
138 | m_value.SetValueType(Value::ValueType::HostAddress); |
139 | break; |
140 | case eAddressTypeInvalid: |
141 | // TODO: does this make sense? |
142 | m_value.SetValueType(Value::ValueType::Scalar); |
143 | break; |
144 | } |
145 | } |
146 | switch (m_value.GetValueType()) { |
147 | case Value::ValueType::Invalid: |
148 | break; |
149 | case Value::ValueType::LoadAddress: |
150 | case Value::ValueType::FileAddress: |
151 | case Value::ValueType::HostAddress: { |
152 | lldb::addr_t addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
153 | if (addr == LLDB_INVALID_ADDRESS) { |
154 | m_error.SetErrorString("parent address is invalid." ); |
155 | } else if (addr == 0) { |
156 | m_error.SetErrorString("parent is NULL" ); |
157 | } else { |
158 | // If a bitfield doesn't fit into the child_byte_size'd window at |
159 | // child_byte_offset, move the window forward until it fits. The |
160 | // problem here is that Value has no notion of bitfields and thus the |
161 | // Value's DataExtractor is sized like the bitfields CompilerType; a |
162 | // sequence of bitfields, however, can be larger than their underlying |
163 | // type. |
164 | if (m_bitfield_bit_offset) { |
165 | const bool thread_and_frame_only_if_stopped = true; |
166 | ExecutionContext exe_ctx(GetExecutionContextRef().Lock( |
167 | thread_and_frame_only_if_stopped)); |
168 | if (auto type_bit_size = 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 = |
204 | value.GetValueAsData(exe_ctx: &exe_ctx, data&: m_data, module: GetModule().get()); |
205 | } else { |
206 | m_error.Clear(); // No value so nothing to read... |
207 | } |
208 | } |
209 | |
210 | } else { |
211 | m_error.SetErrorStringWithFormat("parent failed to evaluate: %s" , |
212 | parent->GetError().AsCString()); |
213 | } |
214 | } else { |
215 | m_error.SetErrorString("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 | |