Index: packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/Makefile =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/Makefile @@ -0,0 +1,15 @@ +LEVEL = ../../../../../make + +CXX_SOURCES := main.cpp + +CXXFLAGS := -O0 +USE_LIBSTDCPP := 1 + +# clang-3.5+ outputs FullDebugInfo by default for Darwin/FreeBSD +# targets. Other targets do not, which causes this test to fail. +# This flag enables FullDebugInfo for all targets. +ifneq (,$(findstring clang,$(CC))) + CFLAGS_EXTRAS += -fno-limit-debug-info +endif + +include $(LEVEL)/Makefile.rules Index: packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/TestDataFormatterStdSmartPtr.py =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/TestDataFormatterStdSmartPtr.py @@ -0,0 +1,45 @@ +""" +Test lldb data formatter subsystem. +""" + +from __future__ import print_function + +import os, time +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class StdSmartPtrDataFormatterTestCase(TestBase): + mydir = TestBase.compute_mydir(__file__) + + @skipIfFreeBSD + @skipIfWindows # libstdcpp not ported to Windows + def test_with_run_command(self): + self.build() + self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_source_regexp (self, "Set break point at this line.") + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', 'stop reason = breakpoint']) + + self.expect("frame variable nsp", substrs = ['nsp = nullptr']) + self.expect("frame variable isp", substrs = ['isp = 123']) + self.expect("frame variable ssp", substrs = ['ssp = "foobar"']) + + self.expect("frame variable nwp", substrs = ['nwp = nullptr']) + self.expect("frame variable iwp", substrs = ['iwp = 123']) + self.expect("frame variable swp", substrs = ['swp = "foobar"']) + + self.runCmd("continue") + + self.expect("frame variable nsp", substrs = ['nsp = nullptr']) + self.expect("frame variable isp", substrs = ['isp = nullptr']) + self.expect("frame variable ssp", substrs = ['ssp = nullptr']) + + self.expect("frame variable nwp", substrs = ['nwp = nullptr']) + self.expect("frame variable iwp", substrs = ['iwp = nullptr']) + self.expect("frame variable swp", substrs = ['swp = nullptr']) Index: packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/main.cpp =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/main.cpp @@ -0,0 +1,18 @@ +#include +#include + +int main() { + std::shared_ptr nsp; + std::shared_ptr isp(new int{123}); + std::shared_ptr ssp = std::make_shared("foobar"); + + std::weak_ptr nwp; + std::weak_ptr iwp = isp; + std::weak_ptr swp = ssp; + + nsp.reset(); // Set break point at this line. + isp.reset(); + ssp.reset(); + + return 0; // Set break point at this line. +} Index: source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp =================================================================== --- source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -652,8 +652,15 @@ "size=${svar%#}"))); AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true); - + AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true); + + AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, "std::shared_ptr synthetic children", ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true); + AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, "std::weak_ptr synthetic children", ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true); + + stl_summary_flags.SetDontShowChildren(true); + AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, "libstdc++ std::shared_ptr summary provider", ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, "libstdc++ std::weak_ptr summary provider", ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true); #endif } Index: source/Plugins/Language/CPlusPlus/LibStdcpp.h =================================================================== --- source/Plugins/Language/CPlusPlus/LibStdcpp.h +++ source/Plugins/Language/CPlusPlus/LibStdcpp.h @@ -23,10 +23,15 @@ bool LibStdcppWStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options); // libcstdc++ c++11 std::wstring + + bool + LibStdcppSmartPointerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options); // libstdc++ std::shared_ptr<> and std::weak_ptr<> SyntheticChildrenFrontEnd* LibstdcppMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP); SyntheticChildrenFrontEnd* LibStdcppVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP); + + SyntheticChildrenFrontEnd* LibStdcppSharedPtrSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP); } // namespace formatters } // namespace lldb_private Index: source/Plugins/Language/CPlusPlus/LibStdcpp.cpp =================================================================== --- source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -28,12 +28,24 @@ using namespace lldb_private; using namespace lldb_private::formatters; +namespace +{ + class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { -public: - LibstdcppMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); + /* + (std::_Rb_tree_iterator, std::allocator > > >) ibeg = { + (_Base_ptr) _M_node = 0x0000000100103910 { + (std::_Rb_tree_color) _M_color = _S_black + (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0 + (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000 + (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000 + } + } + */ - ~LibstdcppMapIteratorSyntheticFrontEnd() override = default; +public: + explicit LibstdcppMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); size_t CalculateNumChildren() override; @@ -57,16 +69,28 @@ lldb::ValueObjectSP m_pair_sp; }; -/* - (std::_Rb_tree_iterator, std::allocator > > >) ibeg = { - (_Base_ptr) _M_node = 0x0000000100103910 { - (std::_Rb_tree_color) _M_color = _S_black - (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0 - (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000 - (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000 - } - } - */ +class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd +{ +public: + explicit LibStdcppSharedPtrSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); + + size_t + CalculateNumChildren() override; + + lldb::ValueObjectSP + GetChildAtIndex(size_t idx) override; + + bool + Update() override; + + bool + MightHaveChildren() override; + + size_t + GetIndexOfChildWithName(const ConstString &name) override; +}; + +} // end of anonymous namespace LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp), @@ -193,7 +217,7 @@ } bool -lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update() +VectorIteratorSyntheticFrontEnd::Update() { m_item_sp.reset(); @@ -218,13 +242,13 @@ } size_t -lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren () +VectorIteratorSyntheticFrontEnd::CalculateNumChildren () { return 1; } lldb::ValueObjectSP -lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx) +VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx) { if (idx == 0) return m_item_sp; @@ -232,20 +256,20 @@ } bool -lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren () +VectorIteratorSyntheticFrontEnd::MightHaveChildren () { return true; } size_t -lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) +VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) { if (name == ConstString("item")) return 0; return UINT32_MAX; } -lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd() = default; +VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd() = default; bool lldb_private::formatters::LibStdcppStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) @@ -360,3 +384,96 @@ } return false; } + +LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : + SyntheticChildrenFrontEnd(*valobj_sp) +{ + if (valobj_sp) + Update(); +} + +size_t +LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren () +{ + return 1; +} + +lldb::ValueObjectSP +LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex (size_t idx) +{ + ValueObjectSP valobj_sp = m_backend.GetSP(); + if (!valobj_sp) + return lldb::ValueObjectSP(); + + if (idx == 0) + return valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true); + else + return lldb::ValueObjectSP(); +} + +bool +LibStdcppSharedPtrSyntheticFrontEnd::Update() +{ + return false; +} + +bool +LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren () +{ + return true; +} + +size_t +LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) +{ + if (name == ConstString("_M_ptr")) + return 0; + return UINT32_MAX; +} + +SyntheticChildrenFrontEnd* +lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) +{ + return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp) : nullptr); +} + +bool +lldb_private::formatters::LibStdcppSmartPointerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) +{ + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true)); + if (!ptr_sp) + return false; + + ValueObjectSP usecount_sp(valobj_sp->GetChildAtNamePath({ConstString("_M_refcount"), + ConstString("_M_pi"), + ConstString("_M_use_count")})); + if (!usecount_sp) + return false; + + if (ptr_sp->GetValueAsUnsigned(0) == 0 || usecount_sp->GetValueAsUnsigned(0) == 0) + { + stream.Printf("nullptr"); + return true; + } + + Error error; + ValueObjectSP pointee_sp = ptr_sp->Dereference(error); + if (pointee_sp && error.Success()) + { + if (pointee_sp->DumpPrintableRepresentation(stream, + ValueObject::eValueObjectRepresentationStyleSummary, + lldb::eFormatInvalid, + ValueObject::ePrintableRepresentationSpecialCasesDisable, + false)) + { + return true; + } + } + + stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); + return true; +}