-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[lldb] add libstdcpp span formatter #168705
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-lldb Author: Ebuka Ezike (da-viper) ChangesFull diff: https://github.com/llvm/llvm-project/pull/168705.diff 5 Files Affected:
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index ca4fd3f680484..c52d3bdb31284 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
+ LibStdcppSpan.cpp
LibStdcppTuple.cpp
LibStdcppUniquePointer.cpp
MsvcStl.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 3cbae1e87f3dc..597cf1e06ffe2 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1411,6 +1411,10 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
stl_synth_flags,
"lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")));
+ AddCXXSynthetic(cpp_category_sp, LibStdcppSpanSyntheticFrontEndCreator,
+ "libstdc++ std::span synthetic children", "^std::span<.+>$",
+ stl_deref_flags, true);
+
stl_summary_flags.SetDontShowChildren(false);
stl_summary_flags.SetSkipPointers(false);
@@ -1501,6 +1505,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
"libstdc++ std::coroutine_handle summary provider",
libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::ContainerSizeSummaryProvider,
+ "libstdc++ std::span summary provider", "^std::span<.+>$",
+ stl_summary_flags, true);
}
static lldb_private::SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
index 429142f63a4bd..8d2c81f2bbcbb 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
@@ -37,6 +37,10 @@ SyntheticChildrenFrontEnd *
LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
+SyntheticChildrenFrontEnd *
+LibStdcppSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
SyntheticChildrenFrontEnd *
LibStdcppTupleSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
new file mode 100644
index 0000000000000..98ea769c78a77
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
@@ -0,0 +1,112 @@
+//===---------------------------------------------------------------------===//
+//
+// 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/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+#include <optional>
+
+using namespace lldb;
+
+namespace lldb_private::formatters {
+
+class LibStdcppSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibStdcppSpanSyntheticFrontEnd(const lldb::ValueObjectSP &valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+ }
+
+ ~LibStdcppSpanSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ return m_num_elements;
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ if (!m_start)
+ return {};
+
+ uint64_t offset = (static_cast<uint64_t>(idx) * m_element_size);
+ offset += m_start->GetValueAsUnsigned(0);
+ const std::string name = llvm::formatv("[{0}]", idx);
+ return CreateValueObjectFromAddress(
+ name, offset, m_backend.GetExecutionContextRef(), m_element_type);
+ }
+
+ lldb::ChildCacheState Update() override {
+ const ValueObjectSP element_ptr =
+ m_backend.GetChildMemberWithName(ConstString("_M_ptr"));
+ if (!element_ptr)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_element_type = element_ptr->GetCompilerType().GetPointeeType();
+
+ // Get element size.
+ llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
+ if (!size_or_err) {
+ LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
+ "{0}");
+ return lldb::ChildCacheState::eReuse;
+ }
+
+ m_element_size = *size_or_err;
+ if (m_element_size > 0) {
+ m_start = element_ptr.get();
+ }
+
+ // Get number of elements.
+ if (auto size_sp = m_backend.GetChildAtNamePath(
+ {ConstString("_M_extent"), ConstString("_M_extent_value")})) {
+ m_num_elements = size_sp->GetValueAsUnsigned(0);
+ } else if (auto arg =
+ m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) {
+
+ m_num_elements = arg->value.GetAPSInt().getLimitedValue();
+ }
+
+ return lldb::ChildCacheState::eReuse;
+ }
+
+ llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
+ if (!m_start)
+ return llvm::createStringError("Type has no child named '%s'",
+ name.AsCString());
+ auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
+ if (!optional_idx) {
+ return llvm::createStringError("Type has no child named '%s'",
+ name.AsCString());
+ }
+ return *optional_idx;
+ }
+
+private:
+ ValueObject *m_start = nullptr; /// First element of span. Held, not owned.
+ CompilerType m_element_type; /// Type of span elements.
+ size_t m_num_elements = 0; /// Number of elements in span.
+ uint32_t m_element_size = 0; /// Size in bytes of each span element.
+};
+
+SyntheticChildrenFrontEnd *
+LibStdcppSpanSyntheticFrontEndCreator(CXXSyntheticChildren * /*unused*/,
+ lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ const CompilerType type = valobj_sp->GetCompilerType();
+ if (!type || type.GetNumTemplateArguments() != 2)
+ return nullptr;
+ return new LibStdcppSpanSyntheticFrontEnd(valobj_sp);
+}
+
+} // namespace lldb_private::formatters
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py
index a45c0ff551323..f586fb3d698c1 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py
@@ -74,7 +74,7 @@ def do_test(self):
result_summary="item 0 is 1",
)
- self.runCmd("type summary delete span")
+ self.runCmd("type summary clear")
# New span with strings
lldbutil.continue_to_breakpoint(process, bkpt)
@@ -155,12 +155,6 @@ def do_test(self):
)
self.check_size("nested", 2)
- @skipIf(compiler="clang", compiler_version=["<", "11.0"])
- @add_test_categories(["libc++"])
- def test_libcxx(self):
- self.build(dictionary={"USE_LIBCPP": 1})
- self.do_test()
-
def do_test_ref_and_ptr(self):
"""Test that std::span is correctly formatted when passed by ref and ptr"""
(self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
@@ -174,8 +168,26 @@ def do_test_ref_and_ptr(self):
self.expect("frame variable ptr", patterns=["ptr = 0x[0-9a-f]+ size=5"])
+ @skipIf(compiler="clang", compiler_version=["<", "11.0"])
+ @add_test_categories(["libc++"])
+ def test_libcxx(self):
+ self.build(dictionary={"USE_LIBCPP": 1})
+ self.do_test()
+
@skipIf(compiler="clang", compiler_version=["<", "11.0"])
@add_test_categories(["libc++"])
def test_ref_and_ptr_libcxx(self):
self.build(dictionary={"USE_LIBCPP": 1})
self.do_test_ref_and_ptr()
+
+ @skipIf(compiler="clang", compiler_version=["<", "11.0"])
+ @add_test_categories(["libstdcxx"])
+ def test_libstdcxx(self):
+ self.build(dictionary={"USE_LIBSTDCPP": 1})
+ self.do_test()
+
+ @skipIf(compiler="clang", compiler_version=["<", "11.0"])
+ @add_test_categories(["libstdcxx"])
+ def test_ref_and_ptr_libstdcxx(self):
+ self.build(dictionary={"USE_LIBSTDCPP": 1})
+ self.do_test_ref_and_ptr()
|
🐧 Linux x64 Test Results
|
| "libstdc++ std::coroutine_handle summary provider", | ||
| libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true); | ||
|
|
||
| AddCXXSummary(cpp_category_sp, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these always on, and used as a fallback then the libcxx one fails?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is on, but it should not match the libcxx version because it has the __1 namespace.
No description provided.