[Lldb-commits] [lldb] [LLDB] Add formatters for MSVC STL unordered containers (PR #149519)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Jul 21 09:01:15 PDT 2025
https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/149519
>From a791fe9b924b1722d11e11a25d940cc7c858a177 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Fri, 18 Jul 2025 16:08:04 +0200
Subject: [PATCH 1/2] [LLDB] Add formatters for MSVC STL unordered containers
---
.../Plugins/Language/CPlusPlus/CMakeLists.txt | 1 +
.../Language/CPlusPlus/CPlusPlusLanguage.cpp | 28 ++++++--
.../Plugins/Language/CPlusPlus/MsvcStl.h | 6 ++
.../Language/CPlusPlus/MsvcStlUnordered.cpp | 69 +++++++++++++++++++
.../TestDataFormatterGenericUnordered.py | 18 +++--
5 files changed, 111 insertions(+), 11 deletions(-)
create mode 100644 lldb/source/Plugins/Language/CPlusPlus/MsvcStlUnordered.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index e1dd5bf84d7eb..dbea81834e976 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -38,6 +38,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
MsvcStlTuple.cpp
MsvcStlVariant.cpp
MsvcStlVector.cpp
+ MsvcStlUnordered.cpp
MSVCUndecoratedNameParser.cpp
LINK_COMPONENTS
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 481fe6106849c..97066f00eb766 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1434,8 +1434,7 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
stl_deref_flags,
"lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
cpp_category_sp->AddTypeSynthetic(
- "^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$",
- eFormatterMatchRegex,
+ "^std::__debug::unordered_(multi)?(map|set)<.+> >$", eFormatterMatchRegex,
SyntheticChildrenSP(new ScriptedSyntheticChildren(
stl_deref_flags,
"lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider")));
@@ -1490,8 +1489,8 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::ContainerSizeSummaryProvider,
- "libstdc++ std unordered container summary provider",
- "^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$",
+ "libstdc++ debug std unordered container summary provider",
+ "^std::__debug::unordered_(multi)?(map|set)<.+> >$",
stl_summary_flags, true);
AddCXXSummary(
@@ -1660,6 +1659,19 @@ static bool GenericVariantSummaryProvider(ValueObject &valobj, Stream &stream,
return LibStdcppVariantSummaryProvider(valobj, stream, options);
}
+static SyntheticChildrenFrontEnd *
+GenericUnorderedSyntheticFrontEndCreator(CXXSyntheticChildren *children,
+ ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+
+ if (IsMsvcStlUnordered(*valobj_sp))
+ return MsvcStlUnorderedSyntheticFrontEndCreator(children, valobj_sp);
+ return new ScriptedSyntheticChildren::FrontEnd(
+ "lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider",
+ *valobj_sp);
+}
+
/// Load formatters that are formatting types from more than one STL
static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
if (!cpp_category_sp)
@@ -1727,6 +1739,10 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
AddCXXSynthetic(cpp_category_sp, GenericVariantSyntheticFrontEndCreator,
"std::variant synthetic children", "^std::variant<.*>$",
stl_synth_flags, true);
+ AddCXXSynthetic(cpp_category_sp, GenericUnorderedSyntheticFrontEndCreator,
+ "std::unordered container synthetic children",
+ "^std::unordered_(multi)?(map|set)<.+> ?>$", stl_synth_flags,
+ true);
SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
stl_deref_flags.SetFrontEndWantsDereference();
@@ -1766,6 +1782,10 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
AddCXXSummary(cpp_category_sp, GenericVariantSummaryProvider,
"MSVC STL/libstdc++ std::variant summary provider",
"^std::variant<.*>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider,
+ "MSVC STL/libstdc++ std unordered container summary provider",
+ "^std::unordered_(multi)?(map|set)<.+> ?>$", stl_summary_flags,
+ true);
}
static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
index 9058d2e579adb..bfffa14b4660d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
@@ -79,6 +79,12 @@ SyntheticChildrenFrontEnd *
MsvcStlVariantSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP valobj_sp);
+// MSVC STL std::unordered_(multi){map|set}<>
+bool IsMsvcStlUnordered(ValueObject &valobj);
+SyntheticChildrenFrontEnd *
+MsvcStlUnorderedSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
+
} // namespace formatters
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlUnordered.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlUnordered.cpp
new file mode 100644
index 0000000000000..9540bff97d260
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlUnordered.cpp
@@ -0,0 +1,69 @@
+//===-- MsvcStlUnordered.cpp ----------------------------------------------===//
+//
+// 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 "MsvcStl.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+class UnorderedFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ UnorderedFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
+ Update();
+ }
+
+ llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
+ if (!m_list_sp)
+ return llvm::createStringError("Missing _List");
+ return m_list_sp->GetIndexOfChildWithName(name);
+ }
+
+ lldb::ChildCacheState Update() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ if (!m_list_sp)
+ return llvm::createStringError("Missing _List");
+ return m_list_sp->GetNumChildren();
+ }
+
+ ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ if (!m_list_sp)
+ return nullptr;
+ return m_list_sp->GetChildAtIndex(idx);
+ }
+
+private:
+ ValueObjectSP m_list_sp;
+};
+
+} // namespace
+
+lldb::ChildCacheState UnorderedFrontEnd::Update() {
+ m_list_sp = nullptr;
+ ValueObjectSP list_sp = m_backend.GetChildMemberWithName("_List");
+ if (!list_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_list_sp = list_sp->GetSyntheticValue();
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool formatters::IsMsvcStlUnordered(ValueObject &valobj) {
+ if (auto valobj_sp = valobj.GetNonSyntheticValue())
+ return valobj_sp->GetChildMemberWithName("_List") != nullptr;
+ return false;
+}
+
+SyntheticChildrenFrontEnd *formatters::MsvcStlUnorderedSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new UnorderedFrontEnd(*valobj_sp);
+ return nullptr;
+}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
index a4209ae069790..d23212443f1fb 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
@@ -2,17 +2,13 @@
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
-USE_LIBSTDCPP = "USE_LIBSTDCPP"
-USE_LIBCPP = "USE_LIBCPP"
-
class GenericUnorderedDataFormatterTestCase(TestBase):
def setUp(self):
TestBase.setUp(self)
self.namespace = "std"
- def do_test_with_run_command(self, stdlib_type):
- self.build(dictionary={stdlib_type: "1"})
+ def do_test_with_run_command(self):
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.")
@@ -127,8 +123,16 @@ def look_for_content_and_continue(self, var_name, patterns):
@add_test_categories(["libstdcxx"])
def test_with_run_command_libstdcpp(self):
- self.do_test_with_run_command(USE_LIBSTDCPP)
+ self.build(dictionary={"USE_LIBSTDCPP": 1})
+ self.do_test_with_run_command()
@add_test_categories(["libc++"])
def test_with_run_command_libcpp(self):
- self.do_test_with_run_command(USE_LIBCPP)
+ self.build(dictionary={"USE_LIBCPP": 1})
+ self.do_test_with_run_command()
+
+ @add_test_categories(["msvcstl"])
+ def test_with_run_command_msvcstl(self):
+ # No flags, because the "msvcstl" category checks that the MSVC STL is used by default.
+ self.build()
+ self.do_test_with_run_command()
>From 79c40f705b4a0e6878b83f83bddf23e6958c5ac8 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Mon, 21 Jul 2025 17:32:02 +0200
Subject: [PATCH 2/2] test: add libstdc++ __debug check
---
.../generic/unordered/TestDataFormatterGenericUnordered.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
index d23212443f1fb..dd740bd43b063 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
@@ -126,6 +126,13 @@ def test_with_run_command_libstdcpp(self):
self.build(dictionary={"USE_LIBSTDCPP": 1})
self.do_test_with_run_command()
+ @add_test_categories(["libstdcxx"])
+ def test_with_run_command_libstdcxx_debug(self):
+ self.build(
+ dictionary={"USE_LIBSTDCPP": 1, "CXXFLAGS_EXTRAS": "-D_GLIBCXX_DEBUG"}
+ )
+ self.do_test_with_run_command()
+
@add_test_categories(["libc++"])
def test_with_run_command_libcpp(self):
self.build(dictionary={"USE_LIBCPP": 1})
More information about the lldb-commits
mailing list