From 205591b164d09fdd39d95af76635a89980ce07e0 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 3 Jul 2025 13:57:20 +0800 Subject: [PATCH 1/3] [lldb][test] Synchronize `__compressed_pair_padding` with libc++ (#142516) This PR mirrors changes of `__compressed_pair_padding` in libc++ into lldb test suite. Related PR for libc++: - #108956 - #109028 - #142125 (cherry picked from commit 119705e5ad2b7e4bfc55f7df9a8fbaa7504aedbd) --- .../compressed_pair.h | 26 +++++++++++++++++-- .../libcxx-simulators/invalid-vector/main.cpp | 2 +- .../TestDataFormatterLibcxxStringSimulator.py | 2 +- .../libcxx-simulators/string/main.cpp | 6 ++--- ...stDataFormatterLibcxxUniquePtrSimulator.py | 2 +- .../libcxx-simulators/unique_ptr/main.cpp | 3 ++- 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h b/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h index 6dc53a4e88ffd..35649b10ce45e 100644 --- a/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h +++ b/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h @@ -58,7 +58,7 @@ class __compressed_pair : private __compressed_pair_elem<_T1, 0>, _T1 &first() { return static_cast<_Base1 &>(*this).__get(); } }; -#elif COMPRESSED_PAIR_REV == 1 +#elif COMPRESSED_PAIR_REV == 1 || COMPRESSED_PAIR_REV == 2 // From libc++ datasizeof.h template struct _FirstPaddingByte { _LLDB_NO_UNIQUE_ADDRESS _Tp __v_; @@ -72,6 +72,9 @@ inline const size_t __datasizeof_v = template struct __lldb_is_final : public integral_constant {}; +// The legacy layout has been patched, see +// https://github.com/llvm/llvm-project/pull/142516. +#if COMPRESSED_PAIR_REV == 1 template class __compressed_pair_padding { char __padding_[((is_empty<_ToPad>::value && !__lldb_is_final<_ToPad>::value) || @@ -79,6 +82,25 @@ template class __compressed_pair_padding { ? 0 : sizeof(_ToPad) - __datasizeof_v<_ToPad>]; }; +#else +template +inline const bool __is_reference_or_unpadded_object = + (std::is_empty<_ToPad>::value && !__lldb_is_final<_ToPad>::value) || + sizeof(_ToPad) == __datasizeof_v<_ToPad>; + +template +inline const bool __is_reference_or_unpadded_object<_Tp &> = true; + +template +inline const bool __is_reference_or_unpadded_object<_Tp &&> = true; + +template > +class __compressed_pair_padding { + char __padding_[sizeof(_ToPad) - __datasizeof_v<_ToPad>] = {}; +}; + +template class __compressed_pair_padding<_ToPad, true> {}; +#endif #define _LLDB_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \ [[__gnu__::__aligned__( \ @@ -96,7 +118,7 @@ template class __compressed_pair_padding { _LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding __padding2_; \ _LLDB_NO_UNIQUE_ADDRESS T3 Initializer3; \ _LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding __padding3_; -#elif COMPRESSED_PAIR_REV == 2 +#elif COMPRESSED_PAIR_REV == 3 #define _LLDB_COMPRESSED_PAIR(T1, Name1, T2, Name2) \ _LLDB_NO_UNIQUE_ADDRESS T1 Name1; \ _LLDB_NO_UNIQUE_ADDRESS T2 Name2 diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp index 3a745883fb49c..f10811817c0d2 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp @@ -1,4 +1,4 @@ -#define COMPRESSED_PAIR_REV 2 +#define COMPRESSED_PAIR_REV 3 #include namespace std { diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/TestDataFormatterLibcxxStringSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/TestDataFormatterLibcxxStringSimulator.py index fff181440b6d7..5bb299153f61f 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/TestDataFormatterLibcxxStringSimulator.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/TestDataFormatterLibcxxStringSimulator.py @@ -28,7 +28,7 @@ def _run_test(self, defines): for v in [None, "ALTERNATE_LAYOUT"]: for r in range(6): - for c in range(3): + for c in range(4): name = "test_r%d_c%d" % (r, c) defines = ["REVISION=%d" % r, "COMPRESSED_PAIR_REV=%d" % c] if v: diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/main.cpp index fdf8d53a34138..cf431e524069c 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/main.cpp @@ -209,7 +209,7 @@ template class basic_string { __long &getLongRep() { #if COMPRESSED_PAIR_REV == 0 return __r_.first().__l; -#elif COMPRESSED_PAIR_REV <= 2 +#elif COMPRESSED_PAIR_REV <= 3 return __rep_.__l; #endif } @@ -217,14 +217,14 @@ template class basic_string { __short &getShortRep() { #if COMPRESSED_PAIR_REV == 0 return __r_.first().__s; -#elif COMPRESSED_PAIR_REV <= 2 +#elif COMPRESSED_PAIR_REV <= 3 return __rep_.__s; #endif } #if COMPRESSED_PAIR_REV == 0 std::__lldb::__compressed_pair<__rep, allocator_type> __r_; -#elif COMPRESSED_PAIR_REV <= 2 +#elif COMPRESSED_PAIR_REV <= 3 _LLDB_COMPRESSED_PAIR(__rep, __rep_, allocator_type, __alloc_); #endif diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py index 0026eca8eebea..a5994bd4df34d 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py @@ -26,7 +26,7 @@ def _run_test(self, defines): ) -for r in range(3): +for r in range(4): name = "test_r%d" % r defines = ["COMPRESSED_PAIR_REV=%d" % r] f = functools.partialmethod( diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp index 91a019566affb..3d174a91cc262 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp @@ -20,7 +20,8 @@ template > class unique_ptr { std::__lldb::__compressed_pair __ptr_; explicit unique_ptr(pointer __p) noexcept : __ptr_(__p, std::__lldb::__value_init_tag()) {} -#elif COMPRESSED_PAIR_REV == 1 || COMPRESSED_PAIR_REV == 2 +#elif COMPRESSED_PAIR_REV == 1 || COMPRESSED_PAIR_REV == 2 || \ + COMPRESSED_PAIR_REV == 3 _LLDB_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_); explicit unique_ptr(pointer __p) noexcept : __ptr_(__p), __deleter_() {} #endif From e4daa06b976f53c6dcd442662aed060c9e30b618 Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Sun, 24 Aug 2025 13:25:58 +0100 Subject: [PATCH 2/3] [lldb][test][NFC] Re-arrange ifdefs in compressed_pair.h In an upcoming patch we'll start supporting a new compressed_pair layout. This refactor will make it easier to add tests for that new layout. (cherry picked from commit 7b22660d2aa0a9906e85d2c25e8a6577c39b31e0) --- .../compressed_pair.h | 96 ++++++++++--------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h b/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h index 35649b10ce45e..491acb52be87d 100644 --- a/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h +++ b/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h @@ -4,6 +4,12 @@ #include #include // for std::forward +// COMPRESSED_PAIR_REV versions: +// 0 -> Post-c88580c layout +// 1 -> Post-27c83382d83dc layout +// 2 -> Post-769c42f4a552a layout +// 3 -> padding-less no_unique_address-based layout (introduced in 27c83382d83dc) + namespace std { namespace __lldb { @@ -13,7 +19,50 @@ namespace __lldb { #define _LLDB_NO_UNIQUE_ADDRESS [[__no_unique_address__]] #endif -#if COMPRESSED_PAIR_REV == 0 // Post-c88580c layout +// From libc++ datasizeof.h +template struct _FirstPaddingByte { + _LLDB_NO_UNIQUE_ADDRESS _Tp __v_; + char __first_padding_byte_; +}; + +template +inline const size_t __datasizeof_v = + __builtin_offsetof(_FirstPaddingByte<_Tp>, __first_padding_byte_); + +template +struct __lldb_is_final : public integral_constant {}; + +// The legacy layout has been patched, see +// https://github.com/llvm/llvm-project/pull/142516. +#if COMPRESSED_PAIR_REV == 1 +template class __compressed_pair_padding { + char __padding_[((is_empty<_ToPad>::value && + !__lldb_is_final<_ToPad>::value) || + is_reference<_ToPad>::value) + ? 0 + : sizeof(_ToPad) - __datasizeof_v<_ToPad>]; +}; +#elif COMPRESSED_PAIR_REV > 1 && COMPRESSED_PAIR_REV < 3 +template +inline const bool __is_reference_or_unpadded_object = + (std::is_empty<_ToPad>::value && !__lldb_is_final<_ToPad>::value) || + sizeof(_ToPad) == __datasizeof_v<_ToPad>; + +template +inline const bool __is_reference_or_unpadded_object<_Tp &> = true; + +template +inline const bool __is_reference_or_unpadded_object<_Tp &&> = true; + +template > +class __compressed_pair_padding { + char __padding_[sizeof(_ToPad) - __datasizeof_v<_ToPad>] = {}; +}; + +template class __compressed_pair_padding<_ToPad, true> {}; +#endif // COMPRESSED_PAIR_REV == 1 + +#if COMPRESSED_PAIR_REV == 0 struct __value_init_tag {}; struct __default_init_tag {}; @@ -59,49 +108,6 @@ class __compressed_pair : private __compressed_pair_elem<_T1, 0>, _T1 &first() { return static_cast<_Base1 &>(*this).__get(); } }; #elif COMPRESSED_PAIR_REV == 1 || COMPRESSED_PAIR_REV == 2 -// From libc++ datasizeof.h -template struct _FirstPaddingByte { - _LLDB_NO_UNIQUE_ADDRESS _Tp __v_; - char __first_padding_byte_; -}; - -template -inline const size_t __datasizeof_v = - __builtin_offsetof(_FirstPaddingByte<_Tp>, __first_padding_byte_); - -template -struct __lldb_is_final : public integral_constant {}; - -// The legacy layout has been patched, see -// https://github.com/llvm/llvm-project/pull/142516. -#if COMPRESSED_PAIR_REV == 1 -template class __compressed_pair_padding { - char __padding_[((is_empty<_ToPad>::value && - !__lldb_is_final<_ToPad>::value) || - is_reference<_ToPad>::value) - ? 0 - : sizeof(_ToPad) - __datasizeof_v<_ToPad>]; -}; -#else -template -inline const bool __is_reference_or_unpadded_object = - (std::is_empty<_ToPad>::value && !__lldb_is_final<_ToPad>::value) || - sizeof(_ToPad) == __datasizeof_v<_ToPad>; - -template -inline const bool __is_reference_or_unpadded_object<_Tp &> = true; - -template -inline const bool __is_reference_or_unpadded_object<_Tp &&> = true; - -template > -class __compressed_pair_padding { - char __padding_[sizeof(_ToPad) - __datasizeof_v<_ToPad>] = {}; -}; - -template class __compressed_pair_padding<_ToPad, true> {}; -#endif - #define _LLDB_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \ [[__gnu__::__aligned__( \ alignof(T2))]] _LLDB_NO_UNIQUE_ADDRESS T1 Initializer1; \ @@ -127,7 +133,7 @@ template class __compressed_pair_padding<_ToPad, true> {}; _LLDB_NO_UNIQUE_ADDRESS T1 Name1; \ _LLDB_NO_UNIQUE_ADDRESS T2 Name2; \ _LLDB_NO_UNIQUE_ADDRESS T3 Name3 -#endif +#endif // COMPRESSED_PAIR_REV == 3 } // namespace __lldb } // namespace std From f3ec20b6108d15bdb999ef7106e7c7f81015f7e5 Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Mon, 25 Aug 2025 17:17:55 +0100 Subject: [PATCH 3/3] [lldb][DataFormatters] Support newer _LIBCPP_COMPRESSED_PAIR layout (#155153) Starting with https://github.com/llvm/llvm-project/pull/154686 the compressed_pair children are now wrapped in an anonymous structure. This patch adjusts the LLDB data-formatters to support that. Outstanding questions: 1. Should GetChildMemberWithName look through anonymous structures? That will break users most likely. But maybe introducing a new API is worth it? Then we wouldnt have to do this awkward passing around of `anon_struct_index` 2. Do we support the layout without the anonymous structure? It's not too much added complexity. And we did release that version of libc++, so there is code out there compiled against it. But there is no great way of testing it (some of our macOS matrix bots do test it i suppose, but not in a targeted way). We have the layout "simulator" tests for some of the STL types which I will adjust. (cherry picked from commit 20dd053160f7d933037aacb69067ef4d77996ba1) --- .../compressed_pair.h | 27 +++++++- .../Plugins/Language/CPlusPlus/LibCxx.cpp | 67 ++++++++++++++----- .../Plugins/Language/CPlusPlus/LibCxx.h | 17 ++++- .../Plugins/Language/CPlusPlus/LibCxxList.cpp | 24 +++---- .../Plugins/Language/CPlusPlus/LibCxxMap.cpp | 29 ++++---- .../Language/CPlusPlus/LibCxxUnorderedMap.cpp | 59 ++++++---------- .../Language/CPlusPlus/LibCxxVector.cpp | 12 ++-- .../libcxx-simulators/invalid-vector/main.cpp | 2 +- .../TestDataFormatterLibcxxStringSimulator.py | 2 +- .../libcxx-simulators/string/main.cpp | 6 +- ...stDataFormatterLibcxxUniquePtrSimulator.py | 2 +- .../libcxx-simulators/unique_ptr/main.cpp | 3 +- 12 files changed, 150 insertions(+), 100 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h b/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h index 491acb52be87d..a1aa7e1a69f3e 100644 --- a/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h +++ b/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h @@ -8,7 +8,9 @@ // 0 -> Post-c88580c layout // 1 -> Post-27c83382d83dc layout // 2 -> Post-769c42f4a552a layout -// 3 -> padding-less no_unique_address-based layout (introduced in 27c83382d83dc) +// 3 -> Post-f5e687d7bf49c layout +// 4 -> padding-less no_unique_address-based layout (introduced in +// 27c83382d83dc) namespace std { namespace __lldb { @@ -42,7 +44,7 @@ template class __compressed_pair_padding { ? 0 : sizeof(_ToPad) - __datasizeof_v<_ToPad>]; }; -#elif COMPRESSED_PAIR_REV > 1 && COMPRESSED_PAIR_REV < 3 +#elif COMPRESSED_PAIR_REV > 1 && COMPRESSED_PAIR_REV < 4 template inline const bool __is_reference_or_unpadded_object = (std::is_empty<_ToPad>::value && !__lldb_is_final<_ToPad>::value) || @@ -125,6 +127,27 @@ class __compressed_pair : private __compressed_pair_elem<_T1, 0>, _LLDB_NO_UNIQUE_ADDRESS T3 Initializer3; \ _LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding __padding3_; #elif COMPRESSED_PAIR_REV == 3 +#define _LLDB_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \ + struct { \ + [[__gnu__::__aligned__( \ + alignof(T2))]] _LLDB_NO_UNIQUE_ADDRESS T1 Initializer1; \ + _LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding __padding1_; \ + _LLDB_NO_UNIQUE_ADDRESS T2 Initializer2; \ + _LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding __padding2_; \ + } + +#define _LLDB_COMPRESSED_TRIPLE(T1, Initializer1, T2, Initializer2, T3, \ + Initializer3) \ + struct { \ + [[using __gnu__: __aligned__(alignof(T2)), \ + __aligned__(alignof(T3))]] _LLDB_NO_UNIQUE_ADDRESS T1 Initializer1; \ + _LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding __padding1_; \ + _LLDB_NO_UNIQUE_ADDRESS T2 Initializer2; \ + _LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding __padding2_; \ + _LLDB_NO_UNIQUE_ADDRESS T3 Initializer3; \ + _LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding __padding3_; \ + } +#elif COMPRESSED_PAIR_REV == 4 #define _LLDB_COMPRESSED_PAIR(T1, Name1, T2, Name2) \ _LLDB_NO_UNIQUE_ADDRESS T1 Name1; \ _LLDB_NO_UNIQUE_ADDRESS T2 Name2 diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 66b4f04eb71f1..60d21a10dd882 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -49,11 +49,6 @@ static void consumeInlineNamespace(llvm::StringRef &name) { } } -bool lldb_private::formatters::isOldCompressedPairLayout( - ValueObject &pair_obj) { - return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair"); -} - bool lldb_private::formatters::isStdTemplate(ConstString type_name, llvm::StringRef type) { llvm::StringRef name = type_name.GetStringRef(); @@ -105,6 +100,44 @@ lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair( return value; } +std::pair +lldb_private::formatters::GetValueOrOldCompressedPair( + ValueObject &obj, size_t anon_struct_idx, llvm::StringRef child_name, + llvm::StringRef compressed_pair_name) { + auto is_old_compressed_pair = [](ValueObject &pair_obj) -> bool { + return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair"); + }; + + // Try searching the child member in an anonymous structure first. + if (auto unwrapped = obj.GetChildAtIndex(anon_struct_idx)) { + ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name)); + if (node_sp) + return {node_sp, is_old_compressed_pair(*node_sp)}; + } + + // Older versions of libc++ don't wrap the children in anonymous structures. + // Try that instead. + ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name)); + if (node_sp) + return {node_sp, is_old_compressed_pair(*node_sp)}; + + // Try the even older __compressed_pair layout. + + assert(!compressed_pair_name.empty()); + + node_sp = obj.GetChildMemberWithName(compressed_pair_name); + + // Unrecognized layout (possibly older than LLDB supports). + if (!node_sp) + return {nullptr, false}; + + // Expected old compressed_pair layout, but got something else. + if (!is_old_compressed_pair(*node_sp)) + return {nullptr, false}; + + return {node_sp, true}; +} + bool lldb_private::formatters::LibcxxFunctionSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { @@ -205,11 +238,12 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( if (!valobj_sp) return false; - ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_")); + auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair( + *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_"); if (!ptr_sp) return false; - if (isOldCompressedPairLayout(*ptr_sp)) + if (is_compressed_pair) ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp); if (!ptr_sp) @@ -382,13 +416,14 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { if (!valobj_sp) return lldb::ChildCacheState::eRefetch; - ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_")); + auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair( + *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_"); if (!ptr_sp) return lldb::ChildCacheState::eRefetch; // Retrieve the actual pointer and the deleter, and clone them to give them // user-friendly names. - if (isOldCompressedPairLayout(*ptr_sp)) { + if (is_compressed_pair) { if (ValueObjectSP value_pointer_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp)) m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer")); @@ -442,17 +477,15 @@ enum class StringLayout { CSD, DSC }; } static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) { - if (auto rep_sp = valobj.GetChildMemberWithName("__rep_")) - return rep_sp; - - ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_"); - if (!valobj_r_sp || !valobj_r_sp->GetError().Success()) + auto [valobj_r_sp, is_compressed_pair] = GetValueOrOldCompressedPair( + valobj, /*anon_struct_idx=*/0, "__rep_", "__r_"); + if (!valobj_r_sp) return nullptr; - if (!isOldCompressedPairLayout(*valobj_r_sp)) - return nullptr; + if (is_compressed_pair) + return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp); - return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp); + return valobj_r_sp; } /// Determine the size in bytes of \p valobj (a libc++ std::string object) and diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index 674bf46c938a9..43ad024d6dd4f 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -25,7 +25,22 @@ GetChildMemberWithName(ValueObject &obj, lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair); lldb::ValueObjectSP GetSecondValueOfLibCXXCompressedPair(ValueObject &pair); -bool isOldCompressedPairLayout(ValueObject &pair_obj); + +/// Returns the ValueObjectSP of the child of \c obj. If \c obj has no +/// child named \c child_name, returns the __compressed_pair child instead +/// with \c compressed_pair_name, if one exists. +/// +/// Latest libc++ wrap the compressed children in an anonymous structure. +/// The \c anon_struct_idx indicates the location of this struct. +/// +/// The returned boolean is \c true if the returned child was has an old-style +/// libc++ __compressed_pair layout. +/// +/// If no child was found returns a nullptr. +std::pair +GetValueOrOldCompressedPair(ValueObject &obj, size_t anon_struct_idx, + llvm::StringRef child_name, + llvm::StringRef compressed_pair_name); bool isStdTemplate(ConstString type_name, llvm::StringRef type); bool LibcxxStringSummaryProviderASCII( diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index f33b148249ab9..25c76966a8a01 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -293,11 +293,18 @@ lldb::ChildCacheState ForwardListFrontEnd::Update() { if (err.Fail() || !backend_addr) return lldb::ChildCacheState::eRefetch; - ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_")); + auto list_base_sp = m_backend.GetChildAtIndex(0); + if (!list_base_sp) + return lldb::ChildCacheState::eRefetch; + + // Anonymous strucutre index is in base class at index 0. + auto [impl_sp, is_compressed_pair] = + GetValueOrOldCompressedPair(*list_base_sp, /*anon_struct_idx=*/0, + "__before_begin_", "__before_begin_"); if (!impl_sp) return ChildCacheState::eRefetch; - if (isOldCompressedPairLayout(*impl_sp)) + if (is_compressed_pair) impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp); if (!impl_sp) @@ -320,17 +327,10 @@ llvm::Expected ListFrontEnd::CalculateNumChildren() { if (!m_head || !m_tail || m_node_address == 0) return 0; - ValueObjectSP size_node_sp(m_backend.GetChildMemberWithName("__size_")); - if (!size_node_sp) { - size_node_sp = m_backend.GetChildMemberWithName( - "__size_alloc_"); // pre-compressed_pair rework - - if (!isOldCompressedPairLayout(*size_node_sp)) - return llvm::createStringError("Unexpected std::list layout: expected " - "old __compressed_pair layout."); - + auto [size_node_sp, is_compressed_pair] = GetValueOrOldCompressedPair( + m_backend, /*anon_struct_idx=*/1, "__size_", "__size_alloc_"); + if (is_compressed_pair) size_node_sp = GetFirstValueOfLibCXXCompressedPair(*size_node_sp); - } if (size_node_sp) m_count = size_node_sp->GetValueAsUnsigned(UINT32_MAX); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index ebaf60a16b069..a1afbf198d3bb 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -202,7 +202,8 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd { size_t GetIndexOfChildWithName(ConstString name) override; private: - llvm::Expected CalculateNumChildrenForOldCompressedPairLayout(); + llvm::Expected + CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair); /// Returns the ValueObject for the __tree_node type that /// holds the key/value pair of the node at index \ref idx. @@ -258,16 +259,8 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: llvm::Expected lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: - CalculateNumChildrenForOldCompressedPairLayout() { - ValueObjectSP node_sp(m_tree->GetChildMemberWithName("__pair3_")); - if (!node_sp) - return 0; - - if (!isOldCompressedPairLayout(*node_sp)) - return llvm::createStringError("Unexpected std::map layout: expected " - "old __compressed_pair layout."); - - node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp); + CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair) { + auto node_sp = GetFirstValueOfLibCXXCompressedPair(pair); if (!node_sp) return 0; @@ -285,12 +278,16 @@ llvm::Expected lldb_private::formatters:: if (m_tree == nullptr) return 0; - if (auto node_sp = m_tree->GetChildMemberWithName("__size_")) { - m_count = node_sp->GetValueAsUnsigned(0); - return m_count; - } + auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair( + *m_tree, /*anon_struct_idx=*/2, "__size_", "__pair3_"); + if (!size_sp) + return llvm::createStringError("Unexpected std::map layout"); - return CalculateNumChildrenForOldCompressedPairLayout(); + if (is_compressed_pair) + return CalculateNumChildrenForOldCompressedPairLayout(*size_sp); + + m_count = size_sp->GetValueAsUnsigned(0); + return m_count; } ValueObjectSP diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index 3cb14bf8fda7b..8e02690b29176 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -134,22 +134,17 @@ CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: GetNodeType() { - auto node_sp = m_backend.GetChildAtNamePath({"__table_", "__first_node_"}); - - if (!node_sp) { - auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"}); - if (!p1_sp) - return {}; + auto table_sp = m_backend.GetChildMemberWithName("__table_"); + if (!table_sp) + return {}; - if (!isOldCompressedPairLayout(*p1_sp)) - return {}; + auto [node_sp, is_compressed_pair] = GetValueOrOldCompressedPair( + *table_sp, /*anon_struct_idx=*/1, "__first_node_", "__p1_"); + if (is_compressed_pair) + node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp); - node_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp); - if (!node_sp) - return {}; - } - - assert(node_sp); + if (!node_sp) + return {}; return node_sp->GetCompilerType().GetTypeTemplateArgument(0).GetPointeeType(); } @@ -227,19 +222,15 @@ lldb::ValueObjectSP lldb_private::formatters:: llvm::Expected lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: CalculateNumChildrenImpl(ValueObject &table) { - if (auto size_sp = table.GetChildMemberWithName("__size_")) + auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair( + table, /*anon_struct_idx=*/2, "__size_", "__p2_"); + if (!is_compressed_pair && size_sp) return size_sp->GetValueAsUnsigned(0); - ValueObjectSP p2_sp = table.GetChildMemberWithName("__p2_"); - if (!p2_sp) - return llvm::createStringError( - "Unexpected std::unordered_map layout: __p2_ member not found."); + if (!is_compressed_pair) + return llvm::createStringError("Unsupported std::unordered_map layout."); - if (!isOldCompressedPairLayout(*p2_sp)) - return llvm::createStringError("Unexpected std::unordered_map layout: old " - "__compressed_pair layout not found."); - - ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp); + ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*size_sp); if (!num_elements_sp) return llvm::createStringError( @@ -250,19 +241,13 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: } static ValueObjectSP GetTreePointer(ValueObject &table) { - ValueObjectSP tree_sp = table.GetChildMemberWithName("__first_node_"); - if (!tree_sp) { - ValueObjectSP p1_sp = table.GetChildMemberWithName("__p1_"); - if (!p1_sp) - return nullptr; - - if (!isOldCompressedPairLayout(*p1_sp)) - return nullptr; - - tree_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp); - if (!tree_sp) - return nullptr; - } + auto [tree_sp, is_compressed_pair] = GetValueOrOldCompressedPair( + table, /*anon_struct_idx=*/1, "__first_node_", "__p1_"); + if (is_compressed_pair) + tree_sp = GetFirstValueOfLibCXXCompressedPair(*tree_sp); + + if (!tree_sp) + return nullptr; return tree_sp->GetChildMemberWithName("__next_"); } diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp index e484c595ca5aa..10e298cd63d7a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp @@ -130,17 +130,15 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex( } static ValueObjectSP GetDataPointer(ValueObject &root) { - if (auto cap_sp = root.GetChildMemberWithName("__cap_")) - return cap_sp; - - ValueObjectSP cap_sp = root.GetChildMemberWithName("__end_cap_"); + auto [cap_sp, is_compressed_pair] = GetValueOrOldCompressedPair( + root, /*anon_struct_idx=*/2, "__cap_", "__end_cap_"); if (!cap_sp) return nullptr; - if (!isOldCompressedPairLayout(*cap_sp)) - return nullptr; + if (is_compressed_pair) + return GetFirstValueOfLibCXXCompressedPair(*cap_sp); - return GetFirstValueOfLibCXXCompressedPair(*cap_sp); + return cap_sp; } lldb::ChildCacheState diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp index f10811817c0d2..5943b35deab8b 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp @@ -1,4 +1,4 @@ -#define COMPRESSED_PAIR_REV 3 +#define COMPRESSED_PAIR_REV 4 #include namespace std { diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/TestDataFormatterLibcxxStringSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/TestDataFormatterLibcxxStringSimulator.py index 5bb299153f61f..8e80fb0041752 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/TestDataFormatterLibcxxStringSimulator.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/TestDataFormatterLibcxxStringSimulator.py @@ -28,7 +28,7 @@ def _run_test(self, defines): for v in [None, "ALTERNATE_LAYOUT"]: for r in range(6): - for c in range(4): + for c in range(5): name = "test_r%d_c%d" % (r, c) defines = ["REVISION=%d" % r, "COMPRESSED_PAIR_REV=%d" % c] if v: diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/main.cpp index cf431e524069c..b19c051596705 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/main.cpp @@ -209,7 +209,7 @@ template class basic_string { __long &getLongRep() { #if COMPRESSED_PAIR_REV == 0 return __r_.first().__l; -#elif COMPRESSED_PAIR_REV <= 3 +#else return __rep_.__l; #endif } @@ -217,14 +217,14 @@ template class basic_string { __short &getShortRep() { #if COMPRESSED_PAIR_REV == 0 return __r_.first().__s; -#elif COMPRESSED_PAIR_REV <= 3 +#else return __rep_.__s; #endif } #if COMPRESSED_PAIR_REV == 0 std::__lldb::__compressed_pair<__rep, allocator_type> __r_; -#elif COMPRESSED_PAIR_REV <= 3 +#else _LLDB_COMPRESSED_PAIR(__rep, __rep_, allocator_type, __alloc_); #endif diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py index a5994bd4df34d..68317a2e9bcf0 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py @@ -26,7 +26,7 @@ def _run_test(self, defines): ) -for r in range(4): +for r in range(5): name = "test_r%d" % r defines = ["COMPRESSED_PAIR_REV=%d" % r] f = functools.partialmethod( diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp index 3d174a91cc262..bd840aaceffa9 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp @@ -20,8 +20,7 @@ template > class unique_ptr { std::__lldb::__compressed_pair __ptr_; explicit unique_ptr(pointer __p) noexcept : __ptr_(__p, std::__lldb::__value_init_tag()) {} -#elif COMPRESSED_PAIR_REV == 1 || COMPRESSED_PAIR_REV == 2 || \ - COMPRESSED_PAIR_REV == 3 +#else _LLDB_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_); explicit unique_ptr(pointer __p) noexcept : __ptr_(__p), __deleter_() {} #endif