1717#include " lldb/Utility/Endian.h"
1818#include " lldb/Utility/Status.h"
1919#include " lldb/Utility/Stream.h"
20+ #include " lldb/lldb-enumerations.h"
2021#include " lldb/lldb-forward.h"
2122
2223using namespace lldb ;
@@ -223,11 +224,10 @@ class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
223224
224225 size_t GetIndexOfChildWithName (ConstString name) override ;
225226
226- ~LibCxxMapIteratorSyntheticFrontEnd () override ;
227+ ~LibCxxMapIteratorSyntheticFrontEnd () override = default ;
227228
228229private:
229- ValueObject *m_pair_ptr;
230- lldb::ValueObjectSP m_pair_sp;
230+ ValueObjectSP m_pair_sp = nullptr ;
231231};
232232} // namespace formatters
233233} // namespace lldb_private
@@ -464,125 +464,71 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator(
464464
465465lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
466466 LibCxxMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp)
467- : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() {
467+ : SyntheticChildrenFrontEnd(*valobj_sp) {
468468 if (valobj_sp)
469469 Update ();
470470}
471471
472472lldb::ChildCacheState
473473lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update () {
474474 m_pair_sp.reset ();
475- m_pair_ptr = nullptr ;
476475
477476 ValueObjectSP valobj_sp = m_backend.GetSP ();
478477 if (!valobj_sp)
479478 return lldb::ChildCacheState::eRefetch;
480479
481480 TargetSP target_sp (valobj_sp->GetTargetSP ());
482-
483481 if (!target_sp)
484482 return lldb::ChildCacheState::eRefetch;
485483
486- // this must be a ValueObject* because it is a child of the ValueObject we
487- // are producing children for it if were a ValueObjectSP, we would end up
488- // with a loop (iterator -> synthetic -> child -> parent == iterator) and
489- // that would in turn leak memory by never allowing the ValueObjects to die
490- // and free their memory
491- m_pair_ptr = valobj_sp
492- ->GetValueForExpressionPath (
493- " .__i_.__ptr_->__value_" , nullptr , nullptr ,
494- ValueObject::GetValueForExpressionPathOptions ()
495- .DontCheckDotVsArrowSyntax ()
496- .SetSyntheticChildrenTraversal (
497- ValueObject::GetValueForExpressionPathOptions::
498- SyntheticChildrenTraversal::None),
499- nullptr )
500- .get ();
501-
502- if (!m_pair_ptr) {
503- m_pair_ptr = valobj_sp
504- ->GetValueForExpressionPath (
505- " .__i_.__ptr_" , nullptr , nullptr ,
506- ValueObject::GetValueForExpressionPathOptions ()
507- .DontCheckDotVsArrowSyntax ()
508- .SetSyntheticChildrenTraversal (
509- ValueObject::GetValueForExpressionPathOptions::
510- SyntheticChildrenTraversal::None),
511- nullptr )
512- .get ();
513- if (m_pair_ptr) {
514- auto __i_ (valobj_sp->GetChildMemberWithName (" __i_" ));
515- if (!__i_) {
516- m_pair_ptr = nullptr ;
517- return lldb::ChildCacheState::eRefetch;
518- }
519- CompilerType pair_type (
520- __i_->GetCompilerType ().GetTypeTemplateArgument (0 ));
521- std::string name;
522- uint64_t bit_offset_ptr;
523- uint32_t bitfield_bit_size_ptr;
524- bool is_bitfield_ptr;
525- pair_type = pair_type.GetFieldAtIndex (
526- 0 , name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
527- if (!pair_type) {
528- m_pair_ptr = nullptr ;
529- return lldb::ChildCacheState::eRefetch;
530- }
484+ // m_backend is a std::map::iterator
485+ // ...which is a __map_iterator<__tree_iterator<..., __node_pointer, ...>>
486+ //
487+ // Then, __map_iterator::__i_ is a __tree_iterator
488+ auto tree_iter_sp = valobj_sp->GetChildMemberWithName (" __i_" );
489+ if (!tree_iter_sp)
490+ return lldb::ChildCacheState::eRefetch;
531491
532- auto addr (m_pair_ptr->GetValueAsUnsigned (LLDB_INVALID_ADDRESS));
533- m_pair_ptr = nullptr ;
534- if (addr && addr != LLDB_INVALID_ADDRESS) {
535- auto ts = pair_type.GetTypeSystem ();
536- auto ast_ctx = ts.dyn_cast_or_null <TypeSystemClang>();
537- if (!ast_ctx)
538- return lldb::ChildCacheState::eRefetch;
539-
540- // Mimick layout of std::__tree_iterator::__ptr_ and read it in
541- // from process memory.
542- //
543- // The following shows the contiguous block of memory:
544- //
545- // +-----------------------------+ class __tree_end_node
546- // __ptr_ | pointer __left_; |
547- // +-----------------------------+ class __tree_node_base
548- // | pointer __right_; |
549- // | __parent_pointer __parent_; |
550- // | bool __is_black_; |
551- // +-----------------------------+ class __tree_node
552- // | __node_value_type __value_; | <<< our key/value pair
553- // +-----------------------------+
554- //
555- CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier (
556- llvm::StringRef (),
557- {{" ptr0" ,
558- ast_ctx->GetBasicType (lldb::eBasicTypeVoid).GetPointerType ()},
559- {" ptr1" ,
560- ast_ctx->GetBasicType (lldb::eBasicTypeVoid).GetPointerType ()},
561- {" ptr2" ,
562- ast_ctx->GetBasicType (lldb::eBasicTypeVoid).GetPointerType ()},
563- {" cw" , ast_ctx->GetBasicType (lldb::eBasicTypeBool)},
564- {" payload" , pair_type}});
565- std::optional<uint64_t > size = tree_node_type.GetByteSize (nullptr );
566- if (!size)
567- return lldb::ChildCacheState::eRefetch;
568- WritableDataBufferSP buffer_sp (new DataBufferHeap (*size, 0 ));
569- ProcessSP process_sp (target_sp->GetProcessSP ());
570- Status error;
571- process_sp->ReadMemory (addr, buffer_sp->GetBytes (),
572- buffer_sp->GetByteSize (), error);
573- if (error.Fail ())
574- return lldb::ChildCacheState::eRefetch;
575- DataExtractor extractor (buffer_sp, process_sp->GetByteOrder (),
576- process_sp->GetAddressByteSize ());
577- auto pair_sp = CreateValueObjectFromData (
578- " pair" , extractor, valobj_sp->GetExecutionContextRef (),
579- tree_node_type);
580- if (pair_sp)
581- m_pair_sp = pair_sp->GetChildAtIndex (4 );
582- }
583- }
492+ // Type is __tree_iterator::__node_pointer
493+ // (We could alternatively also get this from the template argument)
494+ auto node_pointer_type =
495+ tree_iter_sp->GetCompilerType ().GetDirectNestedTypeWithName (
496+ " __node_pointer" );
497+ if (!node_pointer_type.IsValid ())
498+ return lldb::ChildCacheState::eRefetch;
499+
500+ // __ptr_ is a __tree_iterator::__iter_pointer
501+ auto iter_pointer_sp = tree_iter_sp->GetChildMemberWithName (" __ptr_" );
502+ if (!iter_pointer_sp)
503+ return lldb::ChildCacheState::eRefetch;
504+
505+ // Cast the __iter_pointer to a __node_pointer (which stores our key/value
506+ // pair)
507+ auto node_pointer_sp = iter_pointer_sp->Cast (node_pointer_type);
508+ if (!node_pointer_sp)
509+ return lldb::ChildCacheState::eRefetch;
510+
511+ auto key_value_sp = node_pointer_sp->GetChildMemberWithName (" __value_" );
512+ if (!key_value_sp)
513+ return lldb::ChildCacheState::eRefetch;
514+
515+ // Create the synthetic child, which is a pair where the key and value can be
516+ // retrieved by querying the synthetic frontend for
517+ // GetIndexOfChildWithName("first") and GetIndexOfChildWithName("second")
518+ // respectively.
519+ //
520+ // std::map stores the actual key/value pair in value_type::__cc_ (or
521+ // previously __cc).
522+ key_value_sp = key_value_sp->Clone (ConstString (" pair" ));
523+ if (key_value_sp->GetNumChildrenIgnoringErrors () == 1 ) {
524+ auto child0_sp = key_value_sp->GetChildAtIndex (0 );
525+ if (child0_sp &&
526+ (child0_sp->GetName () == " __cc_" || child0_sp->GetName () == " __cc" ))
527+ key_value_sp = child0_sp->Clone (ConstString (" pair" ));
584528 }
585529
530+ m_pair_sp = key_value_sp;
531+
586532 return lldb::ChildCacheState::eRefetch;
587533}
588534
@@ -594,11 +540,10 @@ llvm::Expected<uint32_t> lldb_private::formatters::
594540lldb::ValueObjectSP
595541lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex (
596542 uint32_t idx) {
597- if (m_pair_ptr)
598- return m_pair_ptr->GetChildAtIndex (idx);
599- if (m_pair_sp)
600- return m_pair_sp->GetChildAtIndex (idx);
601- return lldb::ValueObjectSP ();
543+ if (!m_pair_sp)
544+ return nullptr ;
545+
546+ return m_pair_sp->GetChildAtIndex (idx);
602547}
603548
604549bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
@@ -608,17 +553,10 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
608553
609554size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
610555 GetIndexOfChildWithName (ConstString name) {
611- if (name == " first" )
612- return 0 ;
613- if (name == " second" )
614- return 1 ;
615- return UINT32_MAX;
616- }
556+ if (!m_pair_sp)
557+ return UINT32_MAX;
617558
618- lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
619- ~LibCxxMapIteratorSyntheticFrontEnd () {
620- // this will be deleted when its parent dies (since it's a child object)
621- // delete m_pair_ptr;
559+ return m_pair_sp->GetIndexOfChildWithName (name);
622560}
623561
624562SyntheticChildrenFrontEnd *
0 commit comments