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

Reply via email to