llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Ebuka Ezike (da-viper) <details> <summary>Changes</summary> --- Full diff: https://github.com/llvm/llvm-project/pull/174218.diff 6 Files Affected: - (modified) lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt (+1) - (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+24-7) - (modified) lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h (+7) - (added) lldb/source/Plugins/Language/CPlusPlus/LibStdcppAtomic.cpp (+122) - (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py (+48) - (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/main.cpp (+13) ``````````diff diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index c52d3bdb31284..159dfc59e4d9a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -31,6 +31,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN LibCxxValarray.cpp LibCxxVector.cpp LibStdcpp.cpp + LibStdcppAtomic.cpp LibStdcppSpan.cpp LibStdcppTuple.cpp LibStdcppUniquePointer.cpp diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index dd3b84e47dec3..8c4a1335dddf3 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1517,6 +1517,24 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { stl_summary_flags, true); } +static lldb_private::SyntheticChildrenFrontEnd * +GenericAtomicSyntheticFrontEndCreator(CXXSyntheticChildren *children, + const lldb::ValueObjectSP &valobj_sp) { + if (!valobj_sp) + return nullptr; + + if (IsMsvcStlAtomic(*valobj_sp)) + return MsvcStlAtomicSyntheticFrontEndCreator(children, valobj_sp); + return LibStdcppAtomicSyntheticFrontEndCreator(children, valobj_sp); +} + +static bool GenericAtomicSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options) { + if (IsMsvcStlAtomic(valobj)) + return MsvcStlAtomicSummaryProvider(valobj, stream, options); + return LibStdcppAtomicSummaryProvider(valobj, stream, options); +} + static lldb_private::SyntheticChildrenFrontEnd * GenericSmartPointerSyntheticFrontEndCreator(CXXSyntheticChildren *children, lldb::ValueObjectSP valobj_sp) { @@ -1714,6 +1732,9 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { }, "MSVC STL/libstdc++ std::wstring summary provider")); + AddCXXSynthetic(cpp_category_sp, GenericAtomicSyntheticFrontEndCreator, + "std::atomic synthetic children", "^std::atomic<.+>$", + stl_synth_flags, true); // NOTE: it is loaded as a common formatter because the libc++ version is not // in the `__1` namespace, hence we need to dispatch based on the class // layout. @@ -1768,6 +1789,9 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider, "std::initializer_list summary provider", "^std::initializer_list<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, GenericAtomicSummaryProvider, + "std::atomic summary provider", "^std::atomic<.+>$", + stl_summary_flags, true); AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider, "MSVC STL/libstdc++ std::shared_ptr summary provider", "^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true); @@ -1882,13 +1906,6 @@ static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { stl_summary_flags.SetDontShowChildren(false); - AddCXXSynthetic(cpp_category_sp, MsvcStlAtomicSyntheticFrontEndCreator, - "MSVC STL std::atomic synthetic children", - "^std::atomic<.+>$", stl_synth_flags, true); - - AddCXXSummary(cpp_category_sp, MsvcStlAtomicSummaryProvider, - "MSVC STL std::atomic summary provider", "^std::atomic<.+>$", - stl_summary_flags, true); AddCXXSynthetic(cpp_category_sp, MsvcStlTreeIterSyntheticFrontEndCreator, "MSVC STL tree iterator synthetic children", "^std::_Tree(_const)?_iterator<.+>(( )?&)?$", stl_synth_flags, diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h index 8d2c81f2bbcbb..e91f91181425a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h @@ -33,10 +33,17 @@ bool LibStdcppVariantSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libstdc++ std::variant<> +bool LibStdcppAtomicSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + SyntheticChildrenFrontEnd * LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd * +LibStdcppAtomicSyntheticFrontEndCreator(CXXSyntheticChildren *, + const lldb::ValueObjectSP &); + SyntheticChildrenFrontEnd * LibStdcppSpanSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppAtomic.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppAtomic.cpp new file mode 100644 index 0000000000000..ff7ee13343873 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppAtomic.cpp @@ -0,0 +1,122 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LibStdcpp.h" + +#include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/ValueObject/ValueObject.h" +#include "lldb/lldb-enumerations.h" + +using namespace lldb; + +namespace lldb_private::formatters { + +class LibStdcppAtomicSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + explicit LibStdcppAtomicSyntheticFrontEnd(const ValueObjectSP &valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), + m_inner_name(ConstString("Value")) {} + + llvm::Expected<uint32_t> CalculateNumChildren() final { + return m_inner ? 1 : 0; + } + + ValueObjectSP GetChildAtIndex(uint32_t idx) final { + if (idx == 0 && m_inner) + return m_inner->GetSP()->Clone(m_inner_name); + + return {}; + } + + lldb::ChildCacheState Update() final { + if (ValueObjectSP value = ContainerFieldName(m_backend)) { + // show the Type, instead of std::__atomic_base<Type>::__Type_type. + value = value->Cast(value->GetCompilerType().GetCanonicalType()); + m_inner = value.get(); + } + + return lldb::ChildCacheState::eRefetch; + } + + llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) final { + if (name == m_inner_name) + return 0; + + return llvm::createStringError("Type has no child named '%s'", + name.AsCString()); + } + + static ValueObjectSP ContainerFieldName(ValueObject &backend_syn) { + const ValueObjectSP non_synthetic = backend_syn.GetNonSyntheticValue(); + if (!non_synthetic || !non_synthetic.get()) + return {}; + ValueObject &backend = *non_synthetic; + + const CompilerType type = backend.GetCompilerType(); + if (!type.IsValid() || type.GetNumTemplateArguments() < 1) + return {}; + + const CompilerType first_type = type.GetTypeTemplateArgument(0); + const lldb::BasicType basic_type = first_type.GetBasicTypeEnumeration(); + if (basic_type == eBasicTypeBool) + return backend.GetChildAtNamePath({"_M_base", "_M_i"}); + + if (first_type.GetTypeInfo() & lldb::eTypeIsFloat) { + // added float types specialization in c++17 + if (const auto child = backend.GetChildMemberWithName("_M_fp")) + return child; + + return backend.GetChildMemberWithName("_M_i"); + } + + if (first_type.IsPointerType()) + return backend.GetChildAtNamePath({"_M_b", "_M_p"}); + + return backend.GetChildMemberWithName("_M_i"); + } + +private: + ConstString m_inner_name; + ValueObject *m_inner{}; +}; + +SyntheticChildrenFrontEnd * +LibStdcppAtomicSyntheticFrontEndCreator(CXXSyntheticChildren * /*unused*/, + const lldb::ValueObjectSP &valobj_sp) { + if (!valobj_sp) + return nullptr; + + auto valobj = valobj_sp->GetNonSyntheticValue(); + if (!valobj || !valobj.get()) + return nullptr; + + auto member = LibStdcppAtomicSyntheticFrontEnd::ContainerFieldName(*valobj); + if (!member || !member.get()) + return nullptr; + + return new LibStdcppAtomicSyntheticFrontEnd(valobj_sp); +} + +bool LibStdcppAtomicSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options) { + + if (const ValueObjectSP atomic_value = + LibStdcppAtomicSyntheticFrontEnd::ContainerFieldName(valobj)) { + std::string summary; + if (atomic_value->GetSummaryAsCString(summary, options) && + !summary.empty()) { + stream << summary; + return true; + } + } + + return false; +} + +} // namespace lldb_private::formatters diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py index 67c2c359c9afb..ddad85b095362 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py @@ -56,6 +56,35 @@ def do_test(self): self.assertEqual(s.GetChildAtIndex(0).GetValueAsUnsigned(0), 1, "s.x == 1") self.assertEqual(s.GetChildAtIndex(1).GetValueAsUnsigned(0), 2, "s.y == 2") + # float + atomic_float = self.get_variable("atomic_float") + val_float = atomic_float.child[0] + self.assertIsNotNone(val_float, msg="atomic_float child is None.") + self.assertAlmostEqual(float(val_float.value), 3.14, places=2) + # double + atomic_double = self.get_variable("atomic_double") + val_float = atomic_double.child[0] + self.assertIsNotNone(val_float, msg="atomic_double child is None.") + self.assertAlmostEqual(float(val_float.value), 6.28, places=2) + + # bool + atomic_bool = self.get_variable("atomic_bool") + val_bool = atomic_bool.child[0] + self.assertIsNotNone(val_bool, msg="atomic_bool child is None.") + self.assertEqual(bool(val_bool.unsigned), True) + + # func + atomic_func = self.get_variable("atomic_func") + val_func = atomic_func.child[0] + self.assertIsNotNone(val_func, msg="atomic_func child is None.") + self.assertNotEqual(val_func.unsigned, 0) + + # pointer + atomic_pointer = self.get_variable("atomic_pointer") + val_pointer = atomic_pointer.child[0] + self.assertIsNotNone(val_pointer, msg="atomic_pointer child is None.") + self.assertNotEqual(val_pointer.unsigned, 0) + # Try printing the child that points to its own parent object. # This should just treat the atomic pointer as a normal pointer. self.expect("frame var p.child", substrs=["Value = 0x"]) @@ -64,12 +93,31 @@ def do_test(self): "frame var p.child.parent", substrs=["p.child.parent = {\n Value = 0x"] ) + def verify_floating_point_equal(self, value: str, expected: float): + self.assertAlmostEqual(float(value), float(expected), places=4) + @skipIf(compiler=["gcc"]) @add_test_categories(["libc++"]) def test_libcxx(self): self.build(dictionary={"USE_LIBCPP": 1}) self.do_test() + @add_test_categories(["libstdcxx"]) + def test_libstdcxx(self): + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test() + + # the data layout is different in new libstdc++ versions + @add_test_categories(["libstdcxx"]) + def test_libstdcxx_11(self): + self.build(dictionary={"USE_LIBSTDCPP": 1, "CXXFLAGS_EXTRAS": "-std=c++11"}) + self.do_test() + + @add_test_categories(["libstdcxx"]) + def test_libstdcxx_17(self): + self.build(dictionary={"USE_LIBSTDCPP": 1, "CXXFLAGS_EXTRAS": "-std=c++17"}) + self.do_test() + @add_test_categories(["msvcstl"]) def test_msvcstl(self): # No flags, because the "msvcstl" category checks that the MSVC STL is used by default. diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/main.cpp index ee77a880a0c5d..01d5db0a8d8c9 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/main.cpp @@ -17,6 +17,9 @@ struct S { int y = 2; }; +static void func() {} +using func_t = void (*)(); + int main() { std::atomic<S> s; s.store(S()); @@ -27,5 +30,15 @@ int main() { // Let the child node know what its parent is. p.child.parent = &p; + // libstdcpp has different layout depending on the data structure + std::atomic<bool> atomic_bool{true}; + std::atomic<float> atomic_float{3.14}; + std::atomic<double> atomic_double{6.28}; + + std::atomic<func_t> atomic_func(func); + + S data; + std::atomic<S *> atomic_pointer{&data}; + return 0; // Set break point at this line. } `````````` </details> https://github.com/llvm/llvm-project/pull/174218 _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
