/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Core/ValueObjectChild.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 45.6k | : ValueObject(parent), m_compiler_type(compiler_type), |
36 | 45.6k | m_byte_size(byte_size), m_byte_offset(byte_offset), |
37 | 45.6k | m_bitfield_bit_size(bitfield_bit_size), |
38 | 45.6k | m_bitfield_bit_offset(bitfield_bit_offset), |
39 | 45.6k | m_is_base_class(is_base_class), m_is_deref_of_parent(is_deref_of_parent), |
40 | 45.6k | m_can_update_with_invalid_exe_ctx() { |
41 | 45.6k | m_name = name; |
42 | 45.6k | SetAddressTypeOfChildren(child_ptr_or_ref_addr_type); |
43 | 45.6k | SetLanguageFlags(language_flags); |
44 | 45.6k | } |
45 | | |
46 | 29.0k | ValueObjectChild::~ValueObjectChild() = default; |
47 | | |
48 | 32 | lldb::ValueType ValueObjectChild::GetValueType() const { |
49 | 32 | return m_parent->GetValueType(); |
50 | 32 | } |
51 | | |
52 | 35.8k | size_t ValueObjectChild::CalculateNumChildren(uint32_t max) { |
53 | 35.8k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
54 | 35.8k | auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); |
55 | 35.8k | return children_count <= max ? children_count : max0 ; |
56 | 35.8k | } |
57 | | |
58 | | static void AdjustForBitfieldness(ConstString &name, |
59 | 127k | uint8_t bitfield_bit_size) { |
60 | 127k | if (name && bitfield_bit_size) |
61 | 1.74k | name.SetString(llvm::formatv("{0}:{1}", name, bitfield_bit_size).str()); |
62 | 127k | } |
63 | | |
64 | 525 | ConstString ValueObjectChild::GetTypeName() { |
65 | 525 | if (m_type_name.IsEmpty()) { |
66 | 290 | m_type_name = GetCompilerType().GetTypeName(); |
67 | 290 | AdjustForBitfieldness(m_type_name, m_bitfield_bit_size); |
68 | 290 | } |
69 | 525 | return m_type_name; |
70 | 525 | } |
71 | | |
72 | 120k | ConstString ValueObjectChild::GetQualifiedTypeName() { |
73 | 120k | ConstString qualified_name = GetCompilerType().GetTypeName(); |
74 | 120k | AdjustForBitfieldness(qualified_name, m_bitfield_bit_size); |
75 | 120k | return qualified_name; |
76 | 120k | } |
77 | | |
78 | 6.78k | ConstString ValueObjectChild::GetDisplayTypeName() { |
79 | 6.78k | ConstString display_name = GetCompilerType().GetDisplayTypeName(); |
80 | 6.78k | AdjustForBitfieldness(display_name, m_bitfield_bit_size); |
81 | 6.78k | return display_name; |
82 | 6.78k | } |
83 | | |
84 | 116M | LazyBool ValueObjectChild::CanUpdateWithInvalidExecutionContext() { |
85 | 116M | if (m_can_update_with_invalid_exe_ctx) |
86 | 116M | return *m_can_update_with_invalid_exe_ctx; |
87 | 44.7k | if (m_parent) { |
88 | 44.7k | ValueObject *opinionated_parent = |
89 | 116M | m_parent->FollowParentChain([](ValueObject *valobj) -> bool { |
90 | 116M | return (valobj->CanUpdateWithInvalidExecutionContext() == |
91 | 116M | eLazyBoolCalculate); |
92 | 116M | }); |
93 | 44.7k | if (opinionated_parent) |
94 | 831 | return *(m_can_update_with_invalid_exe_ctx = |
95 | 831 | opinionated_parent->CanUpdateWithInvalidExecutionContext()); |
96 | 44.7k | } |
97 | 43.8k | return *(m_can_update_with_invalid_exe_ctx = |
98 | 43.8k | this->ValueObject::CanUpdateWithInvalidExecutionContext()); |
99 | 44.7k | } |
100 | | |
101 | 44.9k | bool ValueObjectChild::UpdateValue() { |
102 | 44.9k | m_error.Clear(); |
103 | 44.9k | SetValueIsValid(false); |
104 | 44.9k | ValueObject *parent = m_parent; |
105 | 44.9k | if (parent) { |
106 | 44.9k | if (parent->UpdateValueIfNeeded(false)) { |
107 | 44.9k | m_value.SetCompilerType(GetCompilerType()); |
108 | | |
109 | 44.9k | CompilerType parent_type(parent->GetCompilerType()); |
110 | | // Copy the parent scalar value and the scalar value type |
111 | 44.9k | m_value.GetScalar() = parent->GetValue().GetScalar(); |
112 | 44.9k | m_value.SetValueType(parent->GetValue().GetValueType()); |
113 | | |
114 | 44.9k | Flags parent_type_flags(parent_type.GetTypeInfo()); |
115 | 44.9k | const bool is_instance_ptr_base = |
116 | 44.9k | ((m_is_base_class) && |
117 | 44.9k | (parent_type_flags.AnySet(lldb::eTypeInstanceIsPointer))4.87k ); |
118 | | |
119 | 44.9k | if (parent->GetCompilerType().ShouldTreatScalarValueAsAddress()) { |
120 | 24.4k | m_value.GetScalar() = parent->GetPointerValue(); |
121 | | |
122 | 24.4k | switch (parent->GetAddressTypeOfChildren()) { |
123 | 0 | case eAddressTypeFile: { |
124 | 0 | lldb::ProcessSP process_sp(GetProcessSP()); |
125 | 0 | if (process_sp && process_sp->IsAlive()) |
126 | 0 | m_value.SetValueType(Value::ValueType::LoadAddress); |
127 | 0 | else |
128 | 0 | m_value.SetValueType(Value::ValueType::FileAddress); |
129 | 0 | } break; |
130 | 24.4k | case eAddressTypeLoad: |
131 | 24.4k | m_value.SetValueType(is_instance_ptr_base |
132 | 24.4k | ? Value::ValueType::Scalar0 |
133 | 24.4k | : Value::ValueType::LoadAddress); |
134 | 24.4k | break; |
135 | 0 | case eAddressTypeHost: |
136 | 0 | m_value.SetValueType(Value::ValueType::HostAddress); |
137 | 0 | break; |
138 | 0 | case eAddressTypeInvalid: |
139 | | // TODO: does this make sense? |
140 | 0 | m_value.SetValueType(Value::ValueType::Scalar); |
141 | 0 | break; |
142 | 24.4k | } |
143 | 24.4k | } |
144 | 44.9k | switch (m_value.GetValueType()) { |
145 | 0 | case Value::ValueType::Invalid: |
146 | 0 | break; |
147 | 38.4k | case Value::ValueType::LoadAddress: |
148 | 38.9k | case Value::ValueType::FileAddress: |
149 | 44.9k | case Value::ValueType::HostAddress: { |
150 | 44.9k | lldb::addr_t addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
151 | 44.9k | if (addr == LLDB_INVALID_ADDRESS) { |
152 | 0 | m_error.SetErrorString("parent address is invalid."); |
153 | 44.9k | } else if (addr == 0) { |
154 | 125 | m_error.SetErrorString("parent is NULL"); |
155 | 44.8k | } 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 | 44.8k | if (m_bitfield_bit_offset) { |
163 | 849 | const bool thread_and_frame_only_if_stopped = true; |
164 | 849 | ExecutionContext exe_ctx(GetExecutionContextRef().Lock( |
165 | 849 | thread_and_frame_only_if_stopped)); |
166 | 849 | if (auto type_bit_size = GetCompilerType().GetBitSize( |
167 | 849 | exe_ctx.GetBestExecutionContextScope())) { |
168 | 849 | uint64_t bitfield_end = |
169 | 849 | m_bitfield_bit_size + m_bitfield_bit_offset; |
170 | 849 | if (bitfield_end > *type_bit_size) { |
171 | 10 | uint64_t overhang_bytes = |
172 | 10 | (bitfield_end - *type_bit_size + 7) / 8; |
173 | 10 | m_byte_offset += overhang_bytes; |
174 | 10 | m_bitfield_bit_offset -= overhang_bytes * 8; |
175 | 10 | } |
176 | 849 | } |
177 | 849 | } |
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 | 44.8k | m_value.GetScalar() += m_byte_offset; |
182 | 44.8k | } |
183 | 44.9k | } break; |
184 | | |
185 | 16 | case Value::ValueType::Scalar: |
186 | | // try to extract the child value from the parent's scalar value |
187 | 16 | { |
188 | 16 | Scalar scalar(m_value.GetScalar()); |
189 | 16 | scalar.ExtractBitfield(8 * m_byte_size, 8 * m_byte_offset); |
190 | 16 | m_value.GetScalar() = scalar; |
191 | 16 | } |
192 | 16 | break; |
193 | 44.9k | } |
194 | | |
195 | 44.9k | if (m_error.Success()) { |
196 | 44.8k | const bool thread_and_frame_only_if_stopped = true; |
197 | 44.8k | ExecutionContext exe_ctx( |
198 | 44.8k | GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped)); |
199 | 44.8k | if (GetCompilerType().GetTypeInfo() & lldb::eTypeHasValue) { |
200 | 33.4k | Value &value = is_instance_ptr_base ? m_parent->GetValue()0 : m_value; |
201 | 33.4k | m_error = |
202 | 33.4k | value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); |
203 | 33.4k | } else { |
204 | 11.3k | m_error.Clear(); // No value so nothing to read... |
205 | 11.3k | } |
206 | 44.8k | } |
207 | | |
208 | 44.9k | } else { |
209 | 28 | m_error.SetErrorStringWithFormat("parent failed to evaluate: %s", |
210 | 28 | parent->GetError().AsCString()); |
211 | 28 | } |
212 | 44.9k | } else { |
213 | 0 | m_error.SetErrorString("ValueObjectChild has a NULL parent ValueObject."); |
214 | 0 | } |
215 | | |
216 | 44.9k | return m_error.Success(); |
217 | 44.9k | } |
218 | | |
219 | 52.4k | bool ValueObjectChild::IsInScope() { |
220 | 52.4k | ValueObject *root(GetRoot()); |
221 | 52.4k | if (root) |
222 | 52.4k | return root->IsInScope(); |
223 | 0 | return false; |
224 | 52.4k | } |