https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/97713
>From f6b3e6055a9e2263f61e3f70d7a97ddbb7db5ab0 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 4 Jul 2024 09:30:19 +0200 Subject: [PATCH 1/2] [lldb][DataFormatter][NFC] Move std::map iterator formatter into LibCxxMap.cpp The two formatters follow very similar techniques to retrieve data out of the map. We're changing this for `std::map` in https://github.com/llvm/llvm-project/pull/97579 and plan to change it in the same way for the iterator formatter. Having them in the same place will allow us to re-use some of the logic (and we won't have to repeat some of the clarification comments). --- .../Plugins/Language/CPlusPlus/LibCxx.cpp | 188 ------------------ .../Plugins/Language/CPlusPlus/LibCxx.h | 29 +-- .../Plugins/Language/CPlusPlus/LibCxxMap.cpp | 187 +++++++++++++++++ 3 files changed, 191 insertions(+), 213 deletions(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index ad467c3966e60..05cfa0568c25d 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -202,194 +202,6 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( return true; } -/* - (lldb) fr var ibeg --raw --ptr-depth 1 - (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, - std::__1::basic_string<char, std::__1::char_traits<char>, - std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, - std::__1::basic_string<char, std::__1::char_traits<char>, - std::__1::allocator<char> > >, void *> *, long> >) ibeg = { - __i_ = { - __ptr_ = 0x0000000100103870 { - std::__1::__tree_node_base<void *> = { - std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = { - __left_ = 0x0000000000000000 - } - __right_ = 0x0000000000000000 - __parent_ = 0x00000001001038b0 - __is_black_ = true - } - __value_ = { - first = 0 - second = { std::string } - */ - -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { - if (valobj_sp) - Update(); -} - -lldb::ChildCacheState -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { - m_pair_sp.reset(); - m_pair_ptr = nullptr; - - ValueObjectSP valobj_sp = m_backend.GetSP(); - if (!valobj_sp) - return lldb::ChildCacheState::eRefetch; - - TargetSP target_sp(valobj_sp->GetTargetSP()); - - if (!target_sp) - return lldb::ChildCacheState::eRefetch; - - // this must be a ValueObject* because it is a child of the ValueObject we - // are producing children for it if were a ValueObjectSP, we would end up - // with a loop (iterator -> synthetic -> child -> parent == iterator) and - // that would in turn leak memory by never allowing the ValueObjects to die - // and free their memory - m_pair_ptr = valobj_sp - ->GetValueForExpressionPath( - ".__i_.__ptr_->__value_", nullptr, nullptr, - ValueObject::GetValueForExpressionPathOptions() - .DontCheckDotVsArrowSyntax() - .SetSyntheticChildrenTraversal( - ValueObject::GetValueForExpressionPathOptions:: - SyntheticChildrenTraversal::None), - nullptr) - .get(); - - if (!m_pair_ptr) { - m_pair_ptr = valobj_sp - ->GetValueForExpressionPath( - ".__i_.__ptr_", nullptr, nullptr, - ValueObject::GetValueForExpressionPathOptions() - .DontCheckDotVsArrowSyntax() - .SetSyntheticChildrenTraversal( - ValueObject::GetValueForExpressionPathOptions:: - SyntheticChildrenTraversal::None), - nullptr) - .get(); - if (m_pair_ptr) { - auto __i_(valobj_sp->GetChildMemberWithName("__i_")); - if (!__i_) { - m_pair_ptr = nullptr; - return lldb::ChildCacheState::eRefetch; - } - CompilerType pair_type( - __i_->GetCompilerType().GetTypeTemplateArgument(0)); - std::string name; - uint64_t bit_offset_ptr; - uint32_t bitfield_bit_size_ptr; - bool is_bitfield_ptr; - pair_type = pair_type.GetFieldAtIndex( - 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); - if (!pair_type) { - m_pair_ptr = nullptr; - return lldb::ChildCacheState::eRefetch; - } - - auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); - m_pair_ptr = nullptr; - if (addr && addr != LLDB_INVALID_ADDRESS) { - auto ts = pair_type.GetTypeSystem(); - auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>(); - if (!ast_ctx) - return lldb::ChildCacheState::eRefetch; - - // Mimick layout of std::__tree_iterator::__ptr_ and read it in - // from process memory. - // - // The following shows the contiguous block of memory: - // - // +-----------------------------+ class __tree_end_node - // __ptr_ | pointer __left_; | - // +-----------------------------+ class __tree_node_base - // | pointer __right_; | - // | __parent_pointer __parent_; | - // | bool __is_black_; | - // +-----------------------------+ class __tree_node - // | __node_value_type __value_; | <<< our key/value pair - // +-----------------------------+ - // - CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( - llvm::StringRef(), - {{"ptr0", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr1", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr2", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, - {"payload", pair_type}}); - std::optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); - if (!size) - return lldb::ChildCacheState::eRefetch; - WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); - ProcessSP process_sp(target_sp->GetProcessSP()); - Status error; - process_sp->ReadMemory(addr, buffer_sp->GetBytes(), - buffer_sp->GetByteSize(), error); - if (error.Fail()) - return lldb::ChildCacheState::eRefetch; - DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); - auto pair_sp = CreateValueObjectFromData( - "pair", extractor, valobj_sp->GetExecutionContextRef(), - tree_node_type); - if (pair_sp) - m_pair_sp = pair_sp->GetChildAtIndex(4); - } - } - } - - return lldb::ChildCacheState::eRefetch; -} - -llvm::Expected<uint32_t> lldb_private::formatters:: - LibCxxMapIteratorSyntheticFrontEnd::CalculateNumChildren() { - return 2; -} - -lldb::ValueObjectSP -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( - uint32_t idx) { - if (m_pair_ptr) - return m_pair_ptr->GetChildAtIndex(idx); - if (m_pair_sp) - return m_pair_sp->GetChildAtIndex(idx); - return lldb::ValueObjectSP(); -} - -bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - MightHaveChildren() { - return true; -} - -size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - GetIndexOfChildWithName(ConstString name) { - if (name == "first") - return 0; - if (name == "second") - return 1; - return UINT32_MAX; -} - -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - ~LibCxxMapIteratorSyntheticFrontEnd() { - // this will be deleted when its parent dies (since it's a child object) - // delete m_pair_ptr; -} - -SyntheticChildrenFrontEnd * -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( - CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { - return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) - : nullptr); -} - lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index 7fe15d1bf3f7a..21dba015d1ba1 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -87,31 +87,6 @@ bool LibcxxContainerSummaryProvider(ValueObject &valobj, Stream &stream, bool LibcxxSpanSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); -class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { -public: - LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - - llvm::Expected<uint32_t> CalculateNumChildren() override; - - lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - - lldb::ChildCacheState Update() override; - - bool MightHaveChildren() override; - - size_t GetIndexOfChildWithName(ConstString name) override; - - ~LibCxxMapIteratorSyntheticFrontEnd() override; - -private: - ValueObject *m_pair_ptr; - lldb::ValueObjectSP m_pair_sp; -}; - -SyntheticChildrenFrontEnd * -LibCxxMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, - lldb::ValueObjectSP); - /// Formats libcxx's std::unordered_map iterators /// /// In raw form a std::unordered_map::iterator is represented as follows: @@ -247,6 +222,10 @@ SyntheticChildrenFrontEnd * LibcxxStdMapSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd * +LibCxxMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + SyntheticChildrenFrontEnd * LibcxxStdUnorderedMapSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 6c2bc1a34137a..c2bb3555908be 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -208,6 +208,27 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd { size_t m_count = UINT32_MAX; std::map<size_t, MapIterator> m_iterators; }; + +class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + llvm::Expected<uint32_t> CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + + ~LibCxxMapIteratorSyntheticFrontEnd() override; + +private: + ValueObject *m_pair_ptr; + lldb::ValueObjectSP m_pair_sp; +}; } // namespace formatters } // namespace lldb_private @@ -456,3 +477,169 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator( CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { return (valobj_sp ? new LibcxxStdMapSyntheticFrontEnd(valobj_sp) : nullptr); } + +lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: + LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { + if (valobj_sp) + Update(); +} + +lldb::ChildCacheState +lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { + m_pair_sp.reset(); + m_pair_ptr = nullptr; + + ValueObjectSP valobj_sp = m_backend.GetSP(); + if (!valobj_sp) + return lldb::ChildCacheState::eRefetch; + + TargetSP target_sp(valobj_sp->GetTargetSP()); + + if (!target_sp) + return lldb::ChildCacheState::eRefetch; + + // this must be a ValueObject* because it is a child of the ValueObject we + // are producing children for it if were a ValueObjectSP, we would end up + // with a loop (iterator -> synthetic -> child -> parent == iterator) and + // that would in turn leak memory by never allowing the ValueObjects to die + // and free their memory + m_pair_ptr = valobj_sp + ->GetValueForExpressionPath( + ".__i_.__ptr_->__value_", nullptr, nullptr, + ValueObject::GetValueForExpressionPathOptions() + .DontCheckDotVsArrowSyntax() + .SetSyntheticChildrenTraversal( + ValueObject::GetValueForExpressionPathOptions:: + SyntheticChildrenTraversal::None), + nullptr) + .get(); + + if (!m_pair_ptr) { + m_pair_ptr = valobj_sp + ->GetValueForExpressionPath( + ".__i_.__ptr_", nullptr, nullptr, + ValueObject::GetValueForExpressionPathOptions() + .DontCheckDotVsArrowSyntax() + .SetSyntheticChildrenTraversal( + ValueObject::GetValueForExpressionPathOptions:: + SyntheticChildrenTraversal::None), + nullptr) + .get(); + if (m_pair_ptr) { + auto __i_(valobj_sp->GetChildMemberWithName("__i_")); + if (!__i_) { + m_pair_ptr = nullptr; + return lldb::ChildCacheState::eRefetch; + } + CompilerType pair_type( + __i_->GetCompilerType().GetTypeTemplateArgument(0)); + std::string name; + uint64_t bit_offset_ptr; + uint32_t bitfield_bit_size_ptr; + bool is_bitfield_ptr; + pair_type = pair_type.GetFieldAtIndex( + 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); + if (!pair_type) { + m_pair_ptr = nullptr; + return lldb::ChildCacheState::eRefetch; + } + + auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); + m_pair_ptr = nullptr; + if (addr && addr != LLDB_INVALID_ADDRESS) { + auto ts = pair_type.GetTypeSystem(); + auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>(); + if (!ast_ctx) + return lldb::ChildCacheState::eRefetch; + + // Mimick layout of std::__tree_iterator::__ptr_ and read it in + // from process memory. + // + // The following shows the contiguous block of memory: + // + // +-----------------------------+ class __tree_end_node + // __ptr_ | pointer __left_; | + // +-----------------------------+ class __tree_node_base + // | pointer __right_; | + // | __parent_pointer __parent_; | + // | bool __is_black_; | + // +-----------------------------+ class __tree_node + // | __node_value_type __value_; | <<< our key/value pair + // +-----------------------------+ + // + CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( + llvm::StringRef(), + {{"ptr0", + ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, + {"ptr1", + ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, + {"ptr2", + ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, + {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, + {"payload", pair_type}}); + std::optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); + if (!size) + return lldb::ChildCacheState::eRefetch; + WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); + ProcessSP process_sp(target_sp->GetProcessSP()); + Status error; + process_sp->ReadMemory(addr, buffer_sp->GetBytes(), + buffer_sp->GetByteSize(), error); + if (error.Fail()) + return lldb::ChildCacheState::eRefetch; + DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), + process_sp->GetAddressByteSize()); + auto pair_sp = CreateValueObjectFromData( + "pair", extractor, valobj_sp->GetExecutionContextRef(), + tree_node_type); + if (pair_sp) + m_pair_sp = pair_sp->GetChildAtIndex(4); + } + } + } + + return lldb::ChildCacheState::eRefetch; +} + +llvm::Expected<uint32_t> lldb_private::formatters:: + LibCxxMapIteratorSyntheticFrontEnd::CalculateNumChildren() { + return 2; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + if (m_pair_ptr) + return m_pair_ptr->GetChildAtIndex(idx); + if (m_pair_sp) + return m_pair_sp->GetChildAtIndex(idx); + return lldb::ValueObjectSP(); +} + +bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (name == "first") + return 0; + if (name == "second") + return 1; + return UINT32_MAX; +} + +lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: + ~LibCxxMapIteratorSyntheticFrontEnd() { + // this will be deleted when its parent dies (since it's a child object) + // delete m_pair_ptr; +} + +SyntheticChildrenFrontEnd * +lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) + : nullptr); +} >From ac7a74e913a75b13bda0f26ecea62862e6f48e4e Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 4 Jul 2024 12:49:35 +0200 Subject: [PATCH 2/2] [lldb][DataFormatter] Simplify libc++ std::map::iterator formatter --- .../Plugins/Language/CPlusPlus/LibCxxMap.cpp | 156 +++++------------- .../TestDataFormatterLibccIterator.py | 10 ++ 2 files changed, 52 insertions(+), 114 deletions(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index c2bb3555908be..8655c4c1d505c 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -17,6 +17,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" +#include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" using namespace lldb; @@ -223,11 +224,10 @@ class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { size_t GetIndexOfChildWithName(ConstString name) override; - ~LibCxxMapIteratorSyntheticFrontEnd() override; + ~LibCxxMapIteratorSyntheticFrontEnd() override = default; private: - ValueObject *m_pair_ptr; - lldb::ValueObjectSP m_pair_sp; + ValueObjectSP m_pair_sp = nullptr; }; } // namespace formatters } // namespace lldb_private @@ -480,7 +480,7 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator( lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { + : SyntheticChildrenFrontEnd(*valobj_sp) { if (valobj_sp) Update(); } @@ -488,117 +488,52 @@ lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: lldb::ChildCacheState lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { m_pair_sp.reset(); - m_pair_ptr = nullptr; ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) return lldb::ChildCacheState::eRefetch; TargetSP target_sp(valobj_sp->GetTargetSP()); - if (!target_sp) return lldb::ChildCacheState::eRefetch; - // this must be a ValueObject* because it is a child of the ValueObject we - // are producing children for it if were a ValueObjectSP, we would end up - // with a loop (iterator -> synthetic -> child -> parent == iterator) and - // that would in turn leak memory by never allowing the ValueObjects to die - // and free their memory - m_pair_ptr = valobj_sp - ->GetValueForExpressionPath( - ".__i_.__ptr_->__value_", nullptr, nullptr, - ValueObject::GetValueForExpressionPathOptions() - .DontCheckDotVsArrowSyntax() - .SetSyntheticChildrenTraversal( - ValueObject::GetValueForExpressionPathOptions:: - SyntheticChildrenTraversal::None), - nullptr) - .get(); - - if (!m_pair_ptr) { - m_pair_ptr = valobj_sp - ->GetValueForExpressionPath( - ".__i_.__ptr_", nullptr, nullptr, - ValueObject::GetValueForExpressionPathOptions() - .DontCheckDotVsArrowSyntax() - .SetSyntheticChildrenTraversal( - ValueObject::GetValueForExpressionPathOptions:: - SyntheticChildrenTraversal::None), - nullptr) - .get(); - if (m_pair_ptr) { - auto __i_(valobj_sp->GetChildMemberWithName("__i_")); - if (!__i_) { - m_pair_ptr = nullptr; - return lldb::ChildCacheState::eRefetch; - } - CompilerType pair_type( - __i_->GetCompilerType().GetTypeTemplateArgument(0)); - std::string name; - uint64_t bit_offset_ptr; - uint32_t bitfield_bit_size_ptr; - bool is_bitfield_ptr; - pair_type = pair_type.GetFieldAtIndex( - 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); - if (!pair_type) { - m_pair_ptr = nullptr; - return lldb::ChildCacheState::eRefetch; - } + auto tree_iter_sp = valobj_sp->GetChildMemberWithName("__i_"); + if (!tree_iter_sp) + return lldb::ChildCacheState::eRefetch; - auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); - m_pair_ptr = nullptr; - if (addr && addr != LLDB_INVALID_ADDRESS) { - auto ts = pair_type.GetTypeSystem(); - auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>(); - if (!ast_ctx) - return lldb::ChildCacheState::eRefetch; - - // Mimick layout of std::__tree_iterator::__ptr_ and read it in - // from process memory. - // - // The following shows the contiguous block of memory: - // - // +-----------------------------+ class __tree_end_node - // __ptr_ | pointer __left_; | - // +-----------------------------+ class __tree_node_base - // | pointer __right_; | - // | __parent_pointer __parent_; | - // | bool __is_black_; | - // +-----------------------------+ class __tree_node - // | __node_value_type __value_; | <<< our key/value pair - // +-----------------------------+ - // - CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( - llvm::StringRef(), - {{"ptr0", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr1", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr2", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, - {"payload", pair_type}}); - std::optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); - if (!size) - return lldb::ChildCacheState::eRefetch; - WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); - ProcessSP process_sp(target_sp->GetProcessSP()); - Status error; - process_sp->ReadMemory(addr, buffer_sp->GetBytes(), - buffer_sp->GetByteSize(), error); - if (error.Fail()) - return lldb::ChildCacheState::eRefetch; - DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); - auto pair_sp = CreateValueObjectFromData( - "pair", extractor, valobj_sp->GetExecutionContextRef(), - tree_node_type); - if (pair_sp) - m_pair_sp = pair_sp->GetChildAtIndex(4); - } - } + auto node_pointer_type = + tree_iter_sp->GetCompilerType().GetDirectNestedTypeWithName( + "__node_pointer"); + if (!node_pointer_type.IsValid()) + return lldb::ChildCacheState::eRefetch; + + auto iter_pointer_sp = tree_iter_sp->GetChildMemberWithName("__ptr_"); + if (!iter_pointer_sp) + return lldb::ChildCacheState::eRefetch; + + auto node_pointer_sp = iter_pointer_sp->Cast(node_pointer_type); + if (!node_pointer_sp) + return lldb::ChildCacheState::eRefetch; + + Status err; + node_pointer_sp = node_pointer_sp->Dereference(err); + if (!node_pointer_sp || err.Fail()) + return lldb::ChildCacheState::eRefetch; + + auto key_value_sp = node_pointer_sp->GetChildMemberWithName("__value_"); + if (!key_value_sp) + return lldb::ChildCacheState::eRefetch; + + key_value_sp = key_value_sp->Clone(ConstString("name")); + if (key_value_sp->GetNumChildrenIgnoringErrors() == 1) { + auto child0_sp = key_value_sp->GetChildAtIndex(0); + if (child0_sp && + (child0_sp->GetName() == "__cc_" || child0_sp->GetName() == "__cc")) + key_value_sp = child0_sp->Clone(ConstString("pair")); } + m_pair_sp = key_value_sp; + return lldb::ChildCacheState::eRefetch; } @@ -610,11 +545,10 @@ llvm::Expected<uint32_t> lldb_private::formatters:: lldb::ValueObjectSP lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( uint32_t idx) { - if (m_pair_ptr) - return m_pair_ptr->GetChildAtIndex(idx); - if (m_pair_sp) - return m_pair_sp->GetChildAtIndex(idx); - return lldb::ValueObjectSP(); + if (!m_pair_sp) + return nullptr; + + return m_pair_sp->GetChildAtIndex(idx); } bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: @@ -631,12 +565,6 @@ size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: return UINT32_MAX; } -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - ~LibCxxMapIteratorSyntheticFrontEnd() { - // this will be deleted when its parent dies (since it's a child object) - // delete m_pair_ptr; -} - SyntheticChildrenFrontEnd * lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py index d9e316b9b8f4e..709c899211ca1 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py @@ -54,8 +54,18 @@ def cleanup(): self.expect("frame variable iimI", substrs=["first = 43981", "second = 61681"]) self.expect("expr iimI", substrs=["first = 43981", "second = 61681"]) + self.expect("frame variable iimI.first", substrs=["first = 43981"]) + self.expect("frame variable iimI.first", substrs=["second"], matching=False) + self.expect("frame variable iimI.second", substrs=["second = 61681"]) + self.expect("frame variable iimI.second", substrs=["first"], matching=False) + self.expect("frame variable simI", substrs=['first = "world"', "second = 42"]) self.expect("expr simI", substrs=['first = "world"', "second = 42"]) + self.expect("frame variable simI.first", substrs=['first = "world"']) + self.expect("frame variable simI.first", substrs=["second"], matching=False) + self.expect("frame variable simI.second", substrs=["second = 42"]) + self.expect("frame variable simI.second", substrs=["first"], matching=False) + self.expect("frame variable svI", substrs=['item = "hello"']) self.expect("expr svI", substrs=['item = "hello"']) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits