diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index 3ec3cad4b8178..296159ea28407 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -34,6 +34,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN LibStdcppTuple.cpp LibStdcppUniquePointer.cpp MsvcStl.cpp + MsvcStlSmartPointer.cpp MSVCUndecoratedNameParser.cpp LINK_COMPONENTS diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 17963c0273ba8..79ee9efb26fc0 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1540,16 +1540,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator, "std::unique_ptr synthetic children", "^std::unique_ptr<.+>(( )?&)?$", stl_synth_flags, true); - AddCXXSynthetic( - cpp_category_sp, - lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, - "std::shared_ptr synthetic children", "^std::shared_ptr<.+>(( )?&)?$", - stl_synth_flags, true); - AddCXXSynthetic( - cpp_category_sp, - lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, - "std::weak_ptr synthetic children", "^std::weak_ptr<.+>(( )?&)?$", - stl_synth_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator, @@ -1580,14 +1570,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { lldb_private::formatters::LibStdcppUniquePointerSummaryProvider, "libstdc++ std::unique_ptr summary provider", "^std::unique_ptr<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary(cpp_category_sp, - lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, - "libstdc++ std::shared_ptr summary provider", - "^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary(cpp_category_sp, - lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, - "libstdc++ std::weak_ptr summary provider", - "^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::StdlibCoroutineHandleSummaryProvider, "libstdc++ std::coroutine_handle summary provider", @@ -1611,6 +1593,10 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { .SetDontShowValue(false) .SetShowMembersOneLiner(false) .SetHideItemNames(false); + SyntheticChildren::Flags stl_synth_flags; + stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences( + false); + using StringElementType = StringPrinter::StringElementType; RegisterStdStringSummaryProvider( @@ -1636,6 +1622,20 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { return LibStdcppStringSummaryProvider(valobj, stream, options); }, "MSVC STL/libstdc++ std::wstring summary provider")); + + AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator, + "std::shared_ptr synthetic children", + "^std::shared_ptr<.+>(( )?&)?$", stl_synth_flags, true); + AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator, + "std::weak_ptr synthetic children", + "^std::weak_ptr<.+>(( )?&)?$", stl_synth_flags, true); + + AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider, + "MSVC STL/libstdc++ std::shared_ptr summary provider", + "^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider, + "MSVC STL/libstdc++ std::weak_ptr summary provider", + "^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true); } static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/Generic.cpp b/lldb/source/Plugins/Language/CPlusPlus/Generic.cpp index b237a8a27090c..724271ebfb9f9 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Generic.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/Generic.cpp @@ -7,6 +7,8 @@ //===---------------------------------------------------------------------===// #include "Generic.h" +#include "LibStdcpp.h" +#include "MsvcStl.h" lldb::ValueObjectSP lldb_private::formatters::GetDesugaredSmartPointerValue( ValueObject &ptr, ValueObject &container) { @@ -16,7 +18,23 @@ lldb::ValueObjectSP lldb_private::formatters::GetDesugaredSmartPointerValue( auto arg = container_type.GetTypeTemplateArgument(0); if (!arg) - return nullptr; + // If there isn't enough debug info, use the pointer type as is + return ptr.GetSP(); return ptr.Cast(arg.GetPointerType()); } + +lldb_private::SyntheticChildrenFrontEnd * +lldb_private::formatters::GenericSmartPointerSyntheticFrontEndCreator( + CXXSyntheticChildren *children, lldb::ValueObjectSP valobj_sp) { + if (auto *msvc = MsvcStlSmartPointerSyntheticFrontEndCreator(valobj_sp)) + return msvc; + + return LibStdcppSharedPtrSyntheticFrontEndCreator(children, valobj_sp); +} + +bool lldb_private::formatters::GenericSmartPointerSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + return MsvcStlSmartPointerSummaryProvider(valobj, stream, options) || + LibStdcppSmartPointerSummaryProvider(valobj, stream, options); +} diff --git a/lldb/source/Plugins/Language/CPlusPlus/Generic.h b/lldb/source/Plugins/Language/CPlusPlus/Generic.h index f3946225ed48d..96b8113dacef8 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/Generic.h +++ b/lldb/source/Plugins/Language/CPlusPlus/Generic.h @@ -24,6 +24,13 @@ bool GenericOptionalSummaryProvider(ValueObject &valobj, Stream &stream, lldb::ValueObjectSP GetDesugaredSmartPointerValue(ValueObject &ptr, ValueObject &container); +// std::shared_ptr<>/std::weak_ptr<> +SyntheticChildrenFrontEnd * +GenericSmartPointerSyntheticFrontEndCreator(CXXSyntheticChildren *children, + lldb::ValueObjectSP valobj_sp); +bool GenericSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + } // namespace formatters } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h index e4ed923033aa7..edf3f4e8a5387 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h @@ -29,6 +29,14 @@ bool MsvcStlWStringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // VC 2015+ std::wstring +// MSVC STL std::shared_ptr<> and std::weak_ptr<> +bool IsMsvcStlSmartPointer(ValueObject &valobj); +bool MsvcStlSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + +lldb_private::SyntheticChildrenFrontEnd * +MsvcStlSmartPointerSyntheticFrontEndCreator(lldb::ValueObjectSP valobj_sp); + } // namespace formatters } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp new file mode 100644 index 0000000000000..409caa373f5e2 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp @@ -0,0 +1,168 @@ +//===-- MsvcStlSmartPointer.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 "Generic.h" +#include "MsvcStl.h" + +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/DataFormatters/TypeSynthetic.h" + +using namespace lldb; + +bool lldb_private::formatters::IsMsvcStlSmartPointer(ValueObject &valobj) { + return valobj.GetChildMemberWithName("_Ptr") != nullptr; +} + +bool lldb_private::formatters::MsvcStlSmartPointerSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_Ptr")); + ValueObjectSP ctrl_sp(valobj_sp->GetChildMemberWithName("_Rep")); + if (!ctrl_sp || !ptr_sp) + return false; + + DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options); + + bool success; + uint64_t ctrl_addr = ctrl_sp->GetValueAsUnsigned(0, &success); + // Empty control field (expired) + if (!success || ctrl_addr == 0) + return true; + + uint64_t uses = 0; + if (auto uses_sp = ctrl_sp->GetChildMemberWithName("_Uses")) { + bool success; + uses = uses_sp->GetValueAsUnsigned(0, &success); + if (!success) + return false; + + stream.Printf(" strong=%" PRIu64, uses); + } + + // _Weaks is the number of weak references - (_Uses != 0). + if (auto weak_count_sp = ctrl_sp->GetChildMemberWithName("_Weaks")) { + bool success; + uint64_t count = weak_count_sp->GetValueAsUnsigned(0, &success); + if (!success) + return false; + + stream.Printf(" weak=%" PRIu64, count - (uses != 0)); + } + + return true; +} + +namespace lldb_private { +namespace formatters { + +class MsvcStlSmartPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + llvm::Expected CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + llvm::Expected GetIndexOfChildWithName(ConstString name) override; + + ~MsvcStlSmartPointerSyntheticFrontEnd() override; + +private: + ValueObject *m_ptr_obj = nullptr; +}; + +} // namespace formatters +} // namespace lldb_private + +lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd:: + MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp) { + if (valobj_sp) + Update(); +} + +llvm::Expected lldb_private::formatters:: + MsvcStlSmartPointerSyntheticFrontEnd::CalculateNumChildren() { + return (m_ptr_obj ? 1 : 0); +} + +lldb::ValueObjectSP +lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + if (!m_ptr_obj) + return lldb::ValueObjectSP(); + + ValueObjectSP valobj_sp = m_backend.GetSP(); + if (!valobj_sp) + return lldb::ValueObjectSP(); + + if (idx == 0) + return m_ptr_obj->GetSP(); + + if (idx == 1) { + Status status; + ValueObjectSP value_sp = m_ptr_obj->Dereference(status); + if (status.Success()) + return value_sp; + } + + return lldb::ValueObjectSP(); +} + +lldb::ChildCacheState +lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::Update() { + m_ptr_obj = nullptr; + + ValueObjectSP valobj_sp = m_backend.GetSP(); + if (!valobj_sp) + return lldb::ChildCacheState::eRefetch; + + auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_Ptr"); + if (!ptr_obj_sp) + return lldb::ChildCacheState::eRefetch; + + auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp); + if (!cast_ptr_sp) + return lldb::ChildCacheState::eRefetch; + + m_ptr_obj = cast_ptr_sp->Clone(ConstString("pointer")).get(); + return lldb::ChildCacheState::eRefetch; +} + +llvm::Expected +lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (name == "_Ptr" || name == "pointer") + return 0; + + if (name == "object" || name == "$$dereference$$") + return 1; + + return llvm::createStringError("Type has no child named '%s'", + name.AsCString()); +} + +lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd:: + ~MsvcStlSmartPointerSyntheticFrontEnd() = default; + +lldb_private::SyntheticChildrenFrontEnd * +lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEndCreator( + lldb::ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + + if (!IsMsvcStlSmartPointer(*valobj_sp)) + return nullptr; + + return new MsvcStlSmartPointerSyntheticFrontEnd(valobj_sp); +} diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py index 3d8569da0332e..d71fbf8d5f81a 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py @@ -118,3 +118,9 @@ def test_libcxx(self): def test_libstdcxx(self): self.build(dictionary={"USE_LIBSTDCPP": 1}) 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. + self.build() + self.do_test()