https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/149519
>From a791fe9b924b1722d11e11a25d940cc7c858a177 Mon Sep 17 00:00:00 2001 From: Nerixyz <nerix...@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 024921fd9f96822e03f223f7bd884712e4994c28 Mon Sep 17 00:00:00 2001 From: Nerixyz <nerix...@outlook.de> Date: Mon, 21 Jul 2025 17:32:02 +0200 Subject: [PATCH 2/2] test: add libstdc++ __debug check --- .../unordered/TestDataFormatterGenericUnordered.py | 8 ++++++++ 1 file changed, 8 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..4e0bf159ae84b 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,14 @@ def test_with_run_command_libstdcpp(self): self.build(dictionary={"USE_LIBSTDCPP": 1}) self.do_test_with_run_command() + @add_test_categories(["libstdcxx"]) + @expectedFailureAll # unordered __debug containers are not supported yet + 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}) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits