Index: packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_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/unique_ptr/TestDataFormatterStdUniquePtr.py =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py @@ -0,0 +1,45 @@ +""" +Test lldb data formatter subsystem. +""" + +from __future__ import print_function + +import os +import time +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class StdUniquePtrDataFormatterTestCase(TestBase): + mydir = TestBase.compute_mydir(__file__) + + @skipIfFreeBSD + @skipIfWindows # libstdcpp not ported to Windows + @skipIfDarwin # doesn't compile on Darwin + 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 nup", substrs=['nup = nullptr']) + self.expect("frame variable iup", substrs=['iup = 123', 'object = 123']) + self.expect("frame variable iup.object", substrs=['object = 123']) + self.expect("frame variable sup", substrs=['sup = "foobar"', 'object = "foobar"']) + self.expect("frame variable sup.object", substrs=['object = "foobar"']) + + self.expect("frame variable ndp", substrs=['ndp = nullptr']) + self.expect("frame variable idp", substrs=['idp = 456', 'object = 456', 'deleter = ', 'a = 1', 'b = 2']) + self.expect("frame variable idp.object", substrs=['object = 456']) + self.expect("frame variable idp.deleter", substrs=['a = 1', 'b = 2']) + self.expect("frame variable sdp", substrs=['sdp = "baz"', 'object = "baz"', 'deleter = ', 'a = 3', 'b = 4']) + self.expect("frame variable sdp.object", substrs=['object = "baz"']) + self.expect("frame variable sdp.deleter", substrs=['a = 3', 'b = 4']) Index: packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp @@ -0,0 +1,23 @@ +#include +#include + +struct Deleter { + void operator()(void*) {} + + int a; + int b; +}; + +int +main() +{ + std::unique_ptr nup; + std::unique_ptr iup(new int{123}); + std::unique_ptr sup(new std::string("foobar")); + + std::unique_ptr ndp; + std::unique_ptr idp(new int{456}, Deleter{1, 2}); + std::unique_ptr sdp(new std::string("baz"), Deleter{3, 4}); + + return 0; // Set break point at this line. +} Index: source/Plugins/Language/CPlusPlus/LibStdcpp.h =================================================================== --- source/Plugins/Language/CPlusPlus/LibStdcpp.h +++ source/Plugins/Language/CPlusPlus/LibStdcpp.h @@ -31,6 +31,10 @@ const TypeSummaryOptions &options); // libstdc++ std::shared_ptr<> and std::weak_ptr<> +bool LibStdcppUniquePointerSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // libstdc++ std::unique_ptr<> + SyntheticChildrenFrontEnd * LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -42,6 +46,13 @@ SyntheticChildrenFrontEnd * LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); + +SyntheticChildrenFrontEnd *LibStdcppUniquePtrSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP); + +SyntheticChildrenFrontEnd *LibStdcppTupleSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP); + } // namespace formatters } // namespace lldb_private Index: source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp =================================================================== --- /dev/null +++ source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp @@ -0,0 +1,148 @@ +//===-- LibStdcpp.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LibStdcpp.h" + +#include +#include + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/DataFormatters/TypeSynthetic.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace { + +class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { + public: + explicit LibStdcppUniquePtrSyntheticFrontEnd(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; + + bool GetSummary(Stream &stream, const TypeSummaryOptions &options); + + private: + ValueObjectSP m_ptr_obj; + ValueObjectSP m_obj_obj; + ValueObjectSP m_del_obj; +}; + +} // end of anonymous namespace + +LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd( + lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp) { + Update(); +} + +bool LibStdcppUniquePtrSyntheticFrontEnd::Update() { + ValueObjectSP valobj_backend_sp = m_backend.GetSP(); + if (!valobj_backend_sp) return false; + + ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue(); + if (!valobj_sp) return false; + + ValueObjectSP tuple_sp = + valobj_sp->GetChildMemberWithName(ConstString("_M_t"), true); + if (!tuple_sp) return false; + + std::unique_ptr tuple_frontend( + LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp)); + + m_ptr_obj = tuple_frontend->GetChildAtIndex(0); + if (m_ptr_obj) + m_ptr_obj->SetName(ConstString("pointer")); + + m_del_obj = tuple_frontend->GetChildAtIndex(1); + if (m_del_obj) + m_del_obj->SetName(ConstString("deleter")); + + if (m_ptr_obj) { + Error error; + m_obj_obj = m_ptr_obj->Dereference(error); + if (error.Success()) { + m_obj_obj->SetName(ConstString("object")); + } + } + + return false; +} + +bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; } + +lldb::ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex( + size_t idx) { + if (idx == 0) return m_obj_obj; + if (idx == 1) return m_del_obj; + if (idx == 2) return m_ptr_obj; + return lldb::ValueObjectSP(); +} + +size_t LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() { + if (m_del_obj) return 2; + if (m_ptr_obj && m_ptr_obj->GetValueAsUnsigned(0) != 0) return 1; + return 0; +} + +size_t LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName( + const ConstString &name) { + if (name == ConstString("obj") || name == ConstString("object")) return 0; + if (name == ConstString("del") || name == ConstString("deleter")) return 1; + if (name == ConstString("ptr") || name == ConstString("pointer")) return 2; + return UINT32_MAX; +} + +bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary( + Stream &stream, const TypeSummaryOptions &options) { + if (!m_ptr_obj) return false; + + if (m_ptr_obj->GetValueAsUnsigned(0) == 0) { + stream.Printf("nullptr"); + } else { + Error error; + bool print_pointee = false; + if (m_obj_obj) { + if (m_obj_obj->DumpPrintableRepresentation( + stream, ValueObject::eValueObjectRepresentationStyleSummary, + lldb::eFormatInvalid, + ValueObject::ePrintableRepresentationSpecialCasesDisable, + false)) { + print_pointee = true; + } + } + if (!print_pointee) + stream.Printf("ptr = 0x%" PRIx64, m_ptr_obj->GetValueAsUnsigned(0)); + } + return true; +} + +SyntheticChildrenFrontEnd * +lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp) + : nullptr); +} + +bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP()); + return formatter.GetSummary(stream, options); +}