@@ -52,26 +52,6 @@ class LibcxxStdUnorderedMapSyntheticFrontEnd
52
52
std::vector<std::pair<ValueObject *, uint64_t >> m_elements_cache;
53
53
};
54
54
55
- // / Formats libcxx's std::unordered_map iterators
56
- // /
57
- // / In raw form a std::unordered_map::iterator is represented as follows:
58
- // /
59
- // / (lldb) var it --raw --ptr-depth 1
60
- // / (std::__1::__hash_map_iterator<
61
- // / std::__1::__hash_iterator<
62
- // / std::__1::__hash_node<
63
- // / std::__1::__hash_value_type<
64
- // / std::__1::basic_string<char, std::__1::char_traits<char>,
65
- // / std::__1::allocator<char> >, std::__1::basic_string<char,
66
- // / std::__1::char_traits<char>, std::__1::allocator<char> > >,
67
- // / void *> *> >)
68
- // / it = {
69
- // / __i_ = {
70
- // / __node_ = 0x0000600001700040 {
71
- // / __next_ = 0x0000600001704000
72
- // / }
73
- // / }
74
- // / }
75
55
class LibCxxUnorderedMapIteratorSyntheticFrontEnd
76
56
: public SyntheticChildrenFrontEnd {
77
57
public:
@@ -90,9 +70,6 @@ class LibCxxUnorderedMapIteratorSyntheticFrontEnd
90
70
size_t GetIndexOfChildWithName (ConstString name) override ;
91
71
92
72
private:
93
- ValueObject *m_iter_ptr = nullptr ; // /< Held, not owned. Child of iterator
94
- // /< ValueObject supplied at construction.
95
-
96
73
lldb::ValueObjectSP m_pair_sp; // /< ValueObject for the key/value pair
97
74
// /< that the iterator currently points
98
75
// /< to.
@@ -304,7 +281,6 @@ lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
304
281
lldb::ChildCacheState lldb_private::formatters::
305
282
LibCxxUnorderedMapIteratorSyntheticFrontEnd::Update () {
306
283
m_pair_sp.reset ();
307
- m_iter_ptr = nullptr ;
308
284
309
285
ValueObjectSP valobj_sp = m_backend.GetSP ();
310
286
if (!valobj_sp)
@@ -315,98 +291,66 @@ lldb::ChildCacheState lldb_private::formatters::
315
291
if (!target_sp)
316
292
return lldb::ChildCacheState::eRefetch;
317
293
318
- if (!valobj_sp)
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)
319
302
return lldb::ChildCacheState::eRefetch;
320
303
321
- auto exprPathOptions = ValueObject::GetValueForExpressionPathOptions ()
322
- .DontCheckDotVsArrowSyntax ()
323
- .SetSyntheticChildrenTraversal (
324
- ValueObject::GetValueForExpressionPathOptions::
325
- SyntheticChildrenTraversal::None);
326
-
327
- // This must be a ValueObject* because it is a child of the ValueObject we
328
- // are producing children for it if were a ValueObjectSP, we would end up
329
- // with a loop (iterator -> synthetic -> child -> parent == iterator) and
330
- // that would in turn leak memory by never allowing the ValueObjects to die
331
- // and free their memory.
332
- m_iter_ptr =
333
- valobj_sp
334
- ->GetValueForExpressionPath (" .__i_.__node_" , nullptr , nullptr ,
335
- exprPathOptions, nullptr )
336
- .get ();
337
-
338
- if (m_iter_ptr) {
339
- auto iter_child (valobj_sp->GetChildMemberWithName (" __i_" ));
340
- if (!iter_child) {
341
- m_iter_ptr = nullptr ;
342
- return lldb::ChildCacheState::eRefetch;
343
- }
344
-
345
- CompilerType node_type (iter_child->GetCompilerType ()
346
- .GetTypeTemplateArgument (0 )
347
- .GetPointeeType ());
348
-
349
- CompilerType pair_type (node_type.GetTypeTemplateArgument (0 ));
350
-
351
- std::string name;
352
- uint64_t bit_offset_ptr;
353
- uint32_t bitfield_bit_size_ptr;
354
- bool is_bitfield_ptr;
355
-
356
- pair_type = pair_type.GetFieldAtIndex (
357
- 0 , name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
358
- if (!pair_type) {
359
- m_iter_ptr = nullptr ;
360
- return lldb::ChildCacheState::eRefetch;
361
- }
304
+ // Type is '__hash_iterator<__node_pointer>'
305
+ auto hash_iter_type = hash_iter_sp->GetCompilerType ();
306
+ if (!hash_iter_type.IsValid ())
307
+ return lldb::ChildCacheState::eRefetch;
362
308
363
- uint64_t addr = m_iter_ptr->GetValueAsUnsigned (LLDB_INVALID_ADDRESS);
364
- m_iter_ptr = nullptr ;
309
+ // Type is '__node_pointer'
310
+ auto node_pointer_type = hash_iter_type.GetTypeTemplateArgument (0 );
311
+ if (!node_pointer_type.IsValid ())
312
+ return lldb::ChildCacheState::eRefetch;
365
313
366
- if (addr == 0 || addr == LLDB_INVALID_ADDRESS)
367
- return lldb::ChildCacheState::eRefetch;
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)
318
+ return lldb::ChildCacheState::eRefetch;
368
319
369
- auto ts = pair_type.GetTypeSystem ();
370
- auto ast_ctx = ts.dyn_cast_or_null <TypeSystemClang>();
371
- if (!ast_ctx)
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)
372
331
return lldb::ChildCacheState::eRefetch;
373
332
374
- // Mimick layout of std::__hash_iterator::__node_ and read it in
375
- // from process memory.
376
- //
377
- // The following shows the contiguous block of memory:
378
- //
379
- // +-----------------------------+ class __hash_node_base
380
- // __node_ | __next_pointer __next_; |
381
- // +-----------------------------+ class __hash_node
382
- // | size_t __hash_; |
383
- // | __node_value_type __value_; | <<< our key/value pair
384
- // +-----------------------------+
385
- //
386
- CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier (
387
- llvm::StringRef (),
388
- {{" __next_" ,
389
- ast_ctx->GetBasicType (lldb::eBasicTypeVoid).GetPointerType ()},
390
- {" __hash_" , ast_ctx->GetBasicType (lldb::eBasicTypeUnsignedLongLong)},
391
- {" __value_" , pair_type}});
392
- std::optional<uint64_t > size = tree_node_type.GetByteSize (nullptr );
393
- if (!size)
394
- return lldb::ChildCacheState::eRefetch;
395
- WritableDataBufferSP buffer_sp (new DataBufferHeap (*size, 0 ));
396
- ProcessSP process_sp (target_sp->GetProcessSP ());
397
- Status error;
398
- process_sp->ReadMemory (addr, buffer_sp->GetBytes (),
399
- buffer_sp->GetByteSize (), error);
400
- if (error.Fail ())
333
+ key_value_sp = anon_union_sp->GetChildMemberWithName (" __value_" );
334
+ if (!key_value_sp)
401
335
return lldb::ChildCacheState::eRefetch;
402
- DataExtractor extractor (buffer_sp, process_sp->GetByteOrder (),
403
- process_sp->GetAddressByteSize ());
404
- auto pair_sp = CreateValueObjectFromData (
405
- " pair" , extractor, valobj_sp->GetExecutionContextRef (), tree_node_type);
406
- if (pair_sp)
407
- m_pair_sp = pair_sp->GetChildAtIndex (2 );
408
336
}
409
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
+
410
354
return lldb::ChildCacheState::eRefetch;
411
355
}
412
356
0 commit comments