LLDB mainline
LibCxxUnorderedMap.cpp
Go to the documentation of this file.
1//===-- LibCxxUnorderedMap.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
15#include "lldb/Target/Target.h"
18#include "lldb/Utility/Endian.h"
19#include "lldb/Utility/Status.h"
20#include "lldb/Utility/Stream.h"
21#include "llvm/ADT/StringRef.h"
22
23using namespace lldb;
24using namespace lldb_private;
25using namespace lldb_private::formatters;
26
27namespace lldb_private {
28namespace formatters {
31public:
33
35
36 llvm::Expected<uint32_t> CalculateNumChildren() override;
37
38 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
39
41
42 bool MightHaveChildren() override;
43
44 size_t GetIndexOfChildWithName(ConstString name) override;
45
46private:
49 ValueObject *m_tree = nullptr;
50 size_t m_num_elements = 0;
52 std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache;
53};
54
57public:
59
61
62 llvm::Expected<uint32_t> CalculateNumChildren() override;
63
64 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
65
67
68 bool MightHaveChildren() override;
69
70 size_t GetIndexOfChildWithName(ConstString name) override;
71
72private:
73 lldb::ValueObjectSP m_pair_sp; ///< ValueObject for the key/value pair
74 ///< that the iterator currently points
75 ///< to.
76};
77
78} // namespace formatters
79} // namespace lldb_private
80
83 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(),
84 m_elements_cache() {
85 if (valobj_sp)
86 Update();
87}
88
89llvm::Expected<uint32_t> lldb_private::formatters::
91 return m_num_elements;
92}
93
94static void consumeInlineNamespace(llvm::StringRef &name) {
95 // Delete past an inline namespace, if any: __[a-zA-Z0-9_]+::
96 auto scratch = name;
97 if (scratch.consume_front("__") && std::isalnum(scratch[0])) {
98 scratch = scratch.drop_while([](char c) { return std::isalnum(c); });
99 if (scratch.consume_front("::")) {
100 // Successfully consumed a namespace.
101 name = scratch;
102 }
103 }
104}
105
106static bool isStdTemplate(ConstString type_name, llvm::StringRef type) {
107 llvm::StringRef name = type_name.GetStringRef();
108 // The type name may be prefixed with `std::__<inline-namespace>::`.
109 if (name.consume_front("std::"))
111 return name.consume_front(type) && name.starts_with("<");
112}
113
114static bool isUnorderedMap(ConstString type_name) {
115 return isStdTemplate(type_name, "unordered_map") ||
116 isStdTemplate(type_name, "unordered_multimap");
117}
118
121 if (idx >= CalculateNumChildrenIgnoringErrors())
122 return lldb::ValueObjectSP();
123 if (m_tree == nullptr)
124 return lldb::ValueObjectSP();
125
126 while (idx >= m_elements_cache.size()) {
127 if (m_next_element == nullptr)
128 return lldb::ValueObjectSP();
129
131 ValueObjectSP node_sp = m_next_element->Dereference(error);
132 if (!node_sp || error.Fail())
133 return lldb::ValueObjectSP();
134
135 ValueObjectSP value_sp = node_sp->GetChildMemberWithName("__value_");
136 ValueObjectSP hash_sp = node_sp->GetChildMemberWithName("__hash_");
137 if (!hash_sp || !value_sp) {
138 if (!m_element_type) {
139 auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
140 if (!p1_sp)
141 return nullptr;
142
144 if (!first_sp)
145 return nullptr;
146
147 m_element_type = first_sp->GetCompilerType();
148 m_element_type = m_element_type.GetTypeTemplateArgument(0);
149 m_element_type = m_element_type.GetPointeeType();
150 m_node_type = m_element_type;
151 m_element_type = m_element_type.GetTypeTemplateArgument(0);
152 // This synthetic provider is used for both unordered_(multi)map and
153 // unordered_(multi)set. For unordered_map, the element type has an
154 // additional type layer, an internal struct (`__hash_value_type`)
155 // that wraps a std::pair. Peel away the internal wrapper type - whose
156 // structure is of no value to users, to expose the std::pair. This
157 // matches the structure returned by the std::map synthetic provider.
158 if (isUnorderedMap(m_backend.GetTypeName())) {
159 std::string name;
160 CompilerType field_type = m_element_type.GetFieldAtIndex(
161 0, name, nullptr, nullptr, nullptr);
162 CompilerType actual_type = field_type.GetTypedefedType();
163 if (isStdTemplate(actual_type.GetTypeName(), "pair"))
164 m_element_type = actual_type;
165 }
166 }
167 if (!m_node_type)
168 return nullptr;
169 node_sp = m_next_element->Cast(m_node_type.GetPointerType())
170 ->Dereference(error);
171 if (!node_sp || error.Fail())
172 return nullptr;
173
174 hash_sp = node_sp->GetChildMemberWithName("__hash_");
175 if (!hash_sp)
176 return nullptr;
177
178 value_sp = node_sp->GetChildMemberWithName("__value_");
179 if (!value_sp) {
180 // clang-format off
181 // Since D101206 (ba79fb2e1f), libc++ wraps the `__value_` in an
182 // anonymous union.
183 // Child 0: __hash_node_base base class
184 // Child 1: __hash_
185 // Child 2: anonymous union
186 // clang-format on
187 auto anon_union_sp = node_sp->GetChildAtIndex(2);
188 if (!anon_union_sp)
189 return nullptr;
190
191 value_sp = anon_union_sp->GetChildMemberWithName("__value_");
192 if (!value_sp)
193 return nullptr;
194 }
195 }
196 m_elements_cache.push_back(
197 {value_sp.get(), hash_sp->GetValueAsUnsigned(0)});
198 m_next_element = node_sp->GetChildMemberWithName("__next_").get();
199 if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0)
200 m_next_element = nullptr;
201 }
202
203 std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx];
204 if (!val_hash.first)
205 return lldb::ValueObjectSP();
206 StreamString stream;
207 stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
208 DataExtractor data;
210 val_hash.first->GetData(data, error);
211 if (error.Fail())
212 return lldb::ValueObjectSP();
213 const bool thread_and_frame_only_if_stopped = true;
214 ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(
215 thread_and_frame_only_if_stopped);
216 return CreateValueObjectFromData(stream.GetString(), data, exe_ctx,
217 m_element_type);
218}
219
222 m_num_elements = 0;
223 m_next_element = nullptr;
224 m_elements_cache.clear();
225 ValueObjectSP table_sp = m_backend.GetChildMemberWithName("__table_");
226 if (!table_sp)
228
229 ValueObjectSP p2_sp = table_sp->GetChildMemberWithName("__p2_");
230 if (!p2_sp)
232
233 ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
234 if (!num_elements_sp)
236
237 ValueObjectSP p1_sp = table_sp->GetChildMemberWithName("__p1_");
238 if (!p1_sp)
240
242 if (!value_sp)
244
245 m_tree = value_sp->GetChildMemberWithName("__next_").get();
246 if (m_tree == nullptr)
248
249 m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
250
251 if (m_num_elements > 0)
252 m_next_element = m_tree;
253
255}
256
259 return true;
260}
261
264 return ExtractIndexFromString(name.GetCString());
265}
266
270 return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)
271 : nullptr);
272}
273
276 : SyntheticChildrenFrontEnd(*valobj_sp) {
277 if (valobj_sp)
278 Update();
279}
280
283 m_pair_sp.reset();
284
285 ValueObjectSP valobj_sp = m_backend.GetSP();
286 if (!valobj_sp)
288
289 TargetSP target_sp(valobj_sp->GetTargetSP());
290
291 if (!target_sp)
293
294 // Get the unordered_map::iterator
295 // m_backend is an 'unordered_map::iterator', aka a
296 // '__hash_map_iterator<__hash_table::iterator>'
297 //
298 // __hash_map_iterator::__i_ is a __hash_table::iterator (aka
299 // __hash_iterator<__node_pointer>)
300 auto hash_iter_sp = valobj_sp->GetChildMemberWithName("__i_");
301 if (!hash_iter_sp)
303
304 // Type is '__hash_iterator<__node_pointer>'
305 auto hash_iter_type = hash_iter_sp->GetCompilerType();
306 if (!hash_iter_type.IsValid())
308
309 // Type is '__node_pointer'
310 auto node_pointer_type = hash_iter_type.GetTypeTemplateArgument(0);
311 if (!node_pointer_type.IsValid())
313
314 // Cast the __hash_iterator to a __node_pointer (which stores our key/value
315 // pair)
316 auto hash_node_sp = hash_iter_sp->Cast(node_pointer_type);
317 if (!hash_node_sp)
319
320 auto key_value_sp = hash_node_sp->GetChildMemberWithName("__value_");
321 if (!key_value_sp) {
322 // clang-format off
323 // Since D101206 (ba79fb2e1f), libc++ wraps the `__value_` in an
324 // anonymous union.
325 // Child 0: __hash_node_base base class
326 // Child 1: __hash_
327 // Child 2: anonymous union
328 // clang-format on
329 auto anon_union_sp = hash_node_sp->GetChildAtIndex(2);
330 if (!anon_union_sp)
332
333 key_value_sp = anon_union_sp->GetChildMemberWithName("__value_");
334 if (!key_value_sp)
336 }
337
338 // Create the synthetic child, which is a pair where the key and value can be
339 // retrieved by querying the synthetic frontend for
340 // GetIndexOfChildWithName("first") and GetIndexOfChildWithName("second")
341 // respectively.
342 //
343 // std::unordered_map stores the actual key/value pair in
344 // __hash_value_type::__cc_ (or previously __cc).
345 auto potential_child_sp = key_value_sp->Clone(ConstString("pair"));
346 if (potential_child_sp)
347 if (potential_child_sp->GetNumChildrenIgnoringErrors() == 1)
348 if (auto child0_sp = potential_child_sp->GetChildAtIndex(0);
349 child0_sp->GetName() == "__cc_" || child0_sp->GetName() == "__cc")
350 potential_child_sp = child0_sp->Clone(ConstString("pair"));
351
352 m_pair_sp = potential_child_sp;
353
355}
356
357llvm::Expected<uint32_t> lldb_private::formatters::
359 return 2;
360}
361
364 if (m_pair_sp)
365 return m_pair_sp->GetChildAtIndex(idx);
366 return lldb::ValueObjectSP();
367}
368
371 return true;
372}
373
376 if (name == "first")
377 return 0;
378 if (name == "second")
379 return 1;
380 return UINT32_MAX;
381}
382
386 return (valobj_sp ? new LibCxxUnorderedMapIteratorSyntheticFrontEnd(valobj_sp)
387 : nullptr);
388}
static llvm::raw_ostream & error(Stream &strm)
static bool isStdTemplate(ConstString type_name, llvm::StringRef type)
static bool isUnorderedMap(ConstString type_name)
static void consumeInlineNamespace(llvm::StringRef &name)
Generic representation of a type in a programming language.
Definition: CompilerType.h:36
CompilerType GetFieldAtIndex(size_t idx, std::string &name, uint64_t *bit_offset_ptr, uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) const
ConstString GetTypeName(bool BaseOnly=false) const
CompilerType GetTypedefedType() const
If the current object represents a typedef type, get the underlying type.
A uniqued constant string class.
Definition: ConstString.h:40
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:197
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:216
An data extractor class.
Definition: DataExtractor.h:48
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
An error handling class.
Definition: Status.h:44
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:134
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
lldb::ValueObjectSP m_pair_sp
ValueObject for the key/value pair that the iterator currently points to.
std::vector< std::pair< ValueObject *, uint64_t > > m_elements_cache
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
#define UINT32_MAX
Definition: lldb-defines.h:19
SyntheticChildrenFrontEnd * LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
size_t ExtractIndexFromString(const char *item_name)
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair)
Definition: LibCxx.cpp:49
SyntheticChildrenFrontEnd * LibcxxStdUnorderedMapSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:479
std::shared_ptr< lldb_private::Target > TargetSP
Definition: lldb-forward.h:443