/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- LibCxxVector.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 "LibCxx.h" |
10 | | |
11 | | #include "lldb/Core/ValueObject.h" |
12 | | #include "lldb/DataFormatters/FormattersHelpers.h" |
13 | | #include "lldb/Utility/ConstString.h" |
14 | | #include <optional> |
15 | | |
16 | | using namespace lldb; |
17 | | using namespace lldb_private; |
18 | | using namespace lldb_private::formatters; |
19 | | |
20 | | namespace lldb_private { |
21 | | namespace formatters { |
22 | | class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { |
23 | | public: |
24 | | LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); |
25 | | |
26 | | ~LibcxxStdVectorSyntheticFrontEnd() override; |
27 | | |
28 | | size_t CalculateNumChildren() override; |
29 | | |
30 | | lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; |
31 | | |
32 | | bool Update() override; |
33 | | |
34 | | bool MightHaveChildren() override; |
35 | | |
36 | | size_t GetIndexOfChildWithName(ConstString name) override; |
37 | | |
38 | | private: |
39 | | ValueObject *m_start = nullptr; |
40 | | ValueObject *m_finish = nullptr; |
41 | | CompilerType m_element_type; |
42 | | uint32_t m_element_size = 0; |
43 | | }; |
44 | | |
45 | | class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd { |
46 | | public: |
47 | | LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); |
48 | | |
49 | | size_t CalculateNumChildren() override; |
50 | | |
51 | | lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; |
52 | | |
53 | | bool Update() override; |
54 | | |
55 | 0 | bool MightHaveChildren() override { return true; } |
56 | | |
57 | | size_t GetIndexOfChildWithName(ConstString name) override; |
58 | | |
59 | | private: |
60 | | CompilerType m_bool_type; |
61 | | ExecutionContextRef m_exe_ctx_ref; |
62 | | uint64_t m_count = 0; |
63 | | lldb::addr_t m_base_data_address = 0; |
64 | | std::map<size_t, lldb::ValueObjectSP> m_children; |
65 | | }; |
66 | | |
67 | | } // namespace formatters |
68 | | } // namespace lldb_private |
69 | | |
70 | | lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: |
71 | | LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) |
72 | 96 | : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { |
73 | 96 | if (valobj_sp) |
74 | 96 | Update(); |
75 | 96 | } |
76 | | |
77 | | lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: |
78 | 86 | ~LibcxxStdVectorSyntheticFrontEnd() { |
79 | | // these need to stay around because they are child objects who will follow |
80 | | // their parent's life cycle |
81 | | // delete m_start; |
82 | | // delete m_finish; |
83 | 86 | } |
84 | | |
85 | | size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: |
86 | 92 | CalculateNumChildren() { |
87 | 92 | if (!m_start || !m_finish) |
88 | 0 | return 0; |
89 | 92 | uint64_t start_val = m_start->GetValueAsUnsigned(0); |
90 | 92 | uint64_t finish_val = m_finish->GetValueAsUnsigned(0); |
91 | | |
92 | 92 | if (start_val == 0 || finish_val == 086 ) |
93 | 6 | return 0; |
94 | | |
95 | 86 | if (start_val >= finish_val) |
96 | 4 | return 0; |
97 | | |
98 | 82 | size_t num_children = (finish_val - start_val); |
99 | 82 | if (num_children % m_element_size) |
100 | 0 | return 0; |
101 | 82 | return num_children / m_element_size; |
102 | 82 | } |
103 | | |
104 | | lldb::ValueObjectSP |
105 | | lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex( |
106 | 300 | size_t idx) { |
107 | 300 | if (!m_start || !m_finish) |
108 | 0 | return lldb::ValueObjectSP(); |
109 | | |
110 | 300 | uint64_t offset = idx * m_element_size; |
111 | 300 | offset = offset + m_start->GetValueAsUnsigned(0); |
112 | 300 | StreamString name; |
113 | 300 | name.Printf("[%" PRIu64 "]", (uint64_t)idx); |
114 | 300 | return CreateValueObjectFromAddress(name.GetString(), offset, |
115 | 300 | m_backend.GetExecutionContextRef(), |
116 | 300 | m_element_type); |
117 | 300 | } |
118 | | |
119 | 192 | bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() { |
120 | 192 | m_start = m_finish = nullptr; |
121 | 192 | ValueObjectSP data_type_finder_sp( |
122 | 192 | m_backend.GetChildMemberWithName("__end_cap_")); |
123 | 192 | if (!data_type_finder_sp) |
124 | 0 | return false; |
125 | | |
126 | 192 | switch (data_type_finder_sp->GetCompilerType().GetNumDirectBaseClasses()) { |
127 | 0 | case 1: |
128 | | // Assume a pre llvm r300140 __compressed_pair implementation: |
129 | 0 | data_type_finder_sp = |
130 | 0 | data_type_finder_sp->GetChildMemberWithName("__first_"); |
131 | 0 | break; |
132 | 192 | case 2: { |
133 | | // Assume a post llvm r300140 __compressed_pair implementation: |
134 | 192 | ValueObjectSP first_elem_parent_sp = |
135 | 192 | data_type_finder_sp->GetChildAtIndex(0); |
136 | 192 | data_type_finder_sp = |
137 | 192 | first_elem_parent_sp->GetChildMemberWithName("__value_"); |
138 | 192 | break; |
139 | 0 | } |
140 | 0 | default: |
141 | 0 | return false; |
142 | 192 | } |
143 | | |
144 | 192 | if (!data_type_finder_sp) |
145 | 0 | return false; |
146 | 192 | m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType(); |
147 | 192 | if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) { |
148 | 192 | m_element_size = *size; |
149 | | |
150 | 192 | if (m_element_size > 0) { |
151 | | // store raw pointers or end up with a circular dependency |
152 | 192 | m_start = m_backend.GetChildMemberWithName("__begin_").get(); |
153 | 192 | m_finish = m_backend.GetChildMemberWithName("__end_").get(); |
154 | 192 | } |
155 | 192 | } |
156 | 192 | return false; |
157 | 192 | } |
158 | | |
159 | | bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: |
160 | 42 | MightHaveChildren() { |
161 | 42 | return true; |
162 | 42 | } |
163 | | |
164 | | size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: |
165 | 0 | GetIndexOfChildWithName(ConstString name) { |
166 | 0 | if (!m_start || !m_finish) |
167 | 0 | return UINT32_MAX; |
168 | 0 | return ExtractIndexFromString(name.GetCString()); |
169 | 0 | } |
170 | | |
171 | | lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: |
172 | | LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) |
173 | 4 | : SyntheticChildrenFrontEnd(*valobj_sp), m_bool_type(), m_exe_ctx_ref(), |
174 | 4 | m_children() { |
175 | 4 | if (valobj_sp) { |
176 | 4 | Update(); |
177 | 4 | m_bool_type = |
178 | 4 | valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool); |
179 | 4 | } |
180 | 4 | } |
181 | | |
182 | | size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: |
183 | 4 | CalculateNumChildren() { |
184 | 4 | return m_count; |
185 | 4 | } |
186 | | |
187 | | lldb::ValueObjectSP |
188 | | lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex( |
189 | 196 | size_t idx) { |
190 | 196 | auto iter = m_children.find(idx), end = m_children.end(); |
191 | 196 | if (iter != end) |
192 | 0 | return iter->second; |
193 | 196 | if (idx >= m_count) |
194 | 0 | return {}; |
195 | 196 | if (m_base_data_address == 0 || m_count == 0) |
196 | 0 | return {}; |
197 | 196 | if (!m_bool_type) |
198 | 0 | return {}; |
199 | 196 | size_t byte_idx = (idx >> 3); // divide by 8 to get byte index |
200 | 196 | size_t bit_index = (idx & 7); // efficient idx % 8 for bit index |
201 | 196 | lldb::addr_t byte_location = m_base_data_address + byte_idx; |
202 | 196 | ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP()); |
203 | 196 | if (!process_sp) |
204 | 0 | return {}; |
205 | 196 | uint8_t byte = 0; |
206 | 196 | uint8_t mask = 0; |
207 | 196 | Status err; |
208 | 196 | size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err); |
209 | 196 | if (err.Fail() || bytes_read == 0) |
210 | 0 | return {}; |
211 | 196 | mask = 1 << bit_index; |
212 | 196 | bool bit_set = ((byte & mask) != 0); |
213 | 196 | std::optional<uint64_t> size = m_bool_type.GetByteSize(nullptr); |
214 | 196 | if (!size) |
215 | 0 | return {}; |
216 | 196 | WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); |
217 | 196 | if (bit_set && buffer_sp100 && buffer_sp->GetBytes()100 ) { |
218 | | // regardless of endianness, anything non-zero is true |
219 | 100 | *(buffer_sp->GetBytes()) = 1; |
220 | 100 | } |
221 | 196 | StreamString name; |
222 | 196 | name.Printf("[%" PRIu64 "]", (uint64_t)idx); |
223 | 196 | ValueObjectSP retval_sp(CreateValueObjectFromData( |
224 | 196 | name.GetString(), |
225 | 196 | DataExtractor(buffer_sp, process_sp->GetByteOrder(), |
226 | 196 | process_sp->GetAddressByteSize()), |
227 | 196 | m_exe_ctx_ref, m_bool_type)); |
228 | 196 | if (retval_sp) |
229 | 196 | m_children[idx] = retval_sp; |
230 | 196 | return retval_sp; |
231 | 196 | } |
232 | | |
233 | | /*(std::__1::vector<std::__1::allocator<bool> >) vBool = { |
234 | | __begin_ = 0x00000001001000e0 |
235 | | __size_ = 56 |
236 | | __cap_alloc_ = { |
237 | | std::__1::__libcpp_compressed_pair_imp<unsigned long, |
238 | | std::__1::allocator<unsigned long> > = { |
239 | | __first_ = 1 |
240 | | } |
241 | | } |
242 | | }*/ |
243 | | |
244 | 8 | bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() { |
245 | 8 | m_children.clear(); |
246 | 8 | ValueObjectSP valobj_sp = m_backend.GetSP(); |
247 | 8 | if (!valobj_sp) |
248 | 0 | return false; |
249 | 8 | m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); |
250 | 8 | ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName("__size_")); |
251 | 8 | if (!size_sp) |
252 | 0 | return false; |
253 | 8 | m_count = size_sp->GetValueAsUnsigned(0); |
254 | 8 | if (!m_count) |
255 | 0 | return true; |
256 | 8 | ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName("__begin_")); |
257 | 8 | if (!begin_sp) { |
258 | 0 | m_count = 0; |
259 | 0 | return false; |
260 | 0 | } |
261 | 8 | m_base_data_address = begin_sp->GetValueAsUnsigned(0); |
262 | 8 | if (!m_base_data_address) { |
263 | 0 | m_count = 0; |
264 | 0 | return false; |
265 | 0 | } |
266 | 8 | return false; |
267 | 8 | } |
268 | | |
269 | | size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: |
270 | 0 | GetIndexOfChildWithName(ConstString name) { |
271 | 0 | if (!m_count || !m_base_data_address) |
272 | 0 | return UINT32_MAX; |
273 | 0 | const char *item_name = name.GetCString(); |
274 | 0 | uint32_t idx = ExtractIndexFromString(item_name); |
275 | 0 | if (idx < UINT32_MAX && idx >= CalculateNumChildren()) |
276 | 0 | return UINT32_MAX; |
277 | 0 | return idx; |
278 | 0 | } |
279 | | |
280 | | lldb_private::SyntheticChildrenFrontEnd * |
281 | | lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator( |
282 | 100 | CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { |
283 | 100 | if (!valobj_sp) |
284 | 0 | return nullptr; |
285 | 100 | CompilerType type = valobj_sp->GetCompilerType(); |
286 | 100 | if (!type.IsValid() || type.GetNumTemplateArguments() == 0) |
287 | 0 | return nullptr; |
288 | 100 | CompilerType arg_type = type.GetTypeTemplateArgument(0); |
289 | 100 | if (arg_type.GetTypeName() == "bool") |
290 | 4 | return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp); |
291 | 96 | return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp); |
292 | 100 | } |