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 <stdio.h> |
25 | #include <string.h> |
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() {} |
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(true, &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("{0}:{1}" , name, bitfield_bit_size).str()); |
62 | } |
63 | |
64 | ConstString ValueObjectChild::GetTypeName() { |
65 | if (m_type_name.IsEmpty()) { |
66 | m_type_name = GetCompilerType().GetTypeName(); |
67 | AdjustForBitfieldness(m_type_name, m_bitfield_bit_size); |
68 | } |
69 | return m_type_name; |
70 | } |
71 | |
72 | ConstString ValueObjectChild::GetQualifiedTypeName() { |
73 | ConstString qualified_name = GetCompilerType().GetTypeName(); |
74 | AdjustForBitfieldness(qualified_name, m_bitfield_bit_size); |
75 | return qualified_name; |
76 | } |
77 | |
78 | ConstString ValueObjectChild::GetDisplayTypeName() { |
79 | ConstString display_name = GetCompilerType().GetDisplayTypeName(); |
80 | AdjustForBitfieldness(display_name, m_bitfield_bit_size); |
81 | return display_name; |
82 | } |
83 | |
84 | LazyBool ValueObjectChild::CanUpdateWithInvalidExecutionContext() { |
85 | if (m_can_update_with_invalid_exe_ctx.hasValue()) |
86 | return m_can_update_with_invalid_exe_ctx.getValue(); |
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 | .getValue(); |
97 | } |
98 | return (m_can_update_with_invalid_exe_ctx = |
99 | this->ValueObject::CanUpdateWithInvalidExecutionContext()) |
100 | .getValue(); |
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(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(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_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(8 * m_byte_size, 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, m_data, 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 | |