From 3a677b29a3b3f6a2539843db4d56ba59689fc0a0 Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Thu, 25 Feb 2021 13:27:22 -0800 Subject: [PATCH] [lldb] Add deref support to libc++ unique_ptr synthetic Add frame variable dereference suppport to libc++ `std::unique_ptr`. This change allows for commands like `v *thing_up` and `v thing_up->m_id`. These commands now work the same way they would with raw pointers, and as they would with expression. This is done by adding an unaccounted for child member named `$$dereference$$`. Without this change, the command would have to be written as `v *thing_up.__value_` or v thing_up.__value_->m_id` which exposes internal structure and is more clumsy to type. Additionally, the existing tests were updated. See also https://reviews.llvm.org/D97165 which added deref support for `std::shared_ptr`. Differential Revision: https://reviews.llvm.org/D97524 --- lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp | 24 +++-- lldb/source/Plugins/Language/CPlusPlus/LibCxx.h | 2 +- .../unique_ptr/TestDataFormatterLibcxxUniquePtr.py | 102 ++++++++++++++------- .../data-formatter-stl/libcxx/unique_ptr/main.cpp | 7 +- 4 files changed, 95 insertions(+), 40 deletions(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 925076f..8eda422 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -463,7 +463,7 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp), m_compressed_pair_sp() { + : SyntheticChildrenFrontEnd(*valobj_sp) { if (valobj_sp) Update(); } @@ -480,19 +480,27 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator( size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: CalculateNumChildren() { - return (m_compressed_pair_sp ? 1 : 0); + return (m_value_ptr_sp ? 1 : 0); } lldb::ValueObjectSP lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex( size_t idx) { - if (!m_compressed_pair_sp) + if (!m_value_ptr_sp) return lldb::ValueObjectSP(); - if (idx != 0) - return lldb::ValueObjectSP(); + if (idx == 0) + return m_value_ptr_sp; - return m_compressed_pair_sp; + if (idx == 1) { + Status status; + auto value_sp = m_value_ptr_sp->Dereference(status); + if (status.Success()) { + return value_sp; + } + } + + return lldb::ValueObjectSP(); } bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { @@ -505,7 +513,7 @@ bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { if (!ptr_sp) return false; - m_compressed_pair_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + m_value_ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); return false; } @@ -519,6 +527,8 @@ size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: GetIndexOfChildWithName(ConstString name) { if (name == "__value_") return 0; + if (name == "$$dereference$$") + return 1; return UINT32_MAX; } diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index 907025f..99e2065 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -124,7 +124,7 @@ public: ~LibcxxUniquePtrSyntheticFrontEnd() override; private: - lldb::ValueObjectSP m_compressed_pair_sp; + lldb::ValueObjectSP m_value_ptr_sp; }; SyntheticChildrenFrontEnd * diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py index b91e494..825513a 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py @@ -3,45 +3,85 @@ Test lldb data formatter for libc++ std::unique_ptr. """ - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil -class LibcxUniquePtrDataFormatterTestCase(TestBase): + +class TestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @add_test_categories(["libc++"]) - def test_with_run_command(self): - """Test that that file and class static variables display correctly.""" + def test_unique_ptr_variables(self): + """Test `frame variable` output for `std::unique_ptr` types.""" self.build() - (self.target, self.process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here', - lldb.SBFileSpec("main.cpp", False)) - - self.expect("frame variable up_empty", - substrs=['(std::unique_ptr >) up_empty = nullptr {', - '__value_ = ', - '}']) - - self.expect("frame variable up_int", - substrs=['(std::unique_ptr >) up_int = 10 {', - '__value_ = ', - '}']) - - self.expect("frame variable up_int_ref", - substrs=['(std::unique_ptr > &) up_int_ref = 10: {', - '__value_ = ', - '}']) - - self.expect("frame variable up_int_ref_ref", - substrs=['(std::unique_ptr > &&) up_int_ref_ref = 10: {', - '__value_ = ', - '}']) - - self.expect("frame variable up_str", - substrs=['up_str = "hello" {', - '__value_ = ', - '}']) + lldbutil.run_to_source_breakpoint( + self, "// break here", lldb.SBFileSpec("main.cpp") + ) + + valobj = self.expect_var_path( + "up_empty", + type="std::unique_ptr >", + summary="nullptr", + children=[ValueCheck(name="__value_")], + ) + self.assertEqual( + valobj.child[0].GetValueAsUnsigned(lldb.LLDB_INVALID_ADDRESS), 0 + ) + + self.expect( + "frame variable *up_empty", substrs=["(int) *up_empty = "] + ) + + valobj = self.expect_var_path( + "up_int", + type="std::unique_ptr >", + summary="10", + children=[ValueCheck(name="__value_")], + ) + self.assertNotEqual(valobj.child[0].unsigned, 0) + + valobj = self.expect_var_path( + "up_int_ref", + type="std::unique_ptr > &", + summary="10", + children=[ValueCheck(name="__value_")], + ) + self.assertNotEqual(valobj.child[0].unsigned, 0) + + valobj = self.expect_var_path( + "up_int_ref_ref", + type="std::unique_ptr > &&", + summary="10", + children=[ValueCheck(name="__value_")], + ) + self.assertNotEqual(valobj.child[0].unsigned, 0) + + valobj = self.expect_var_path( + "up_str", + type="std::unique_ptr, std::allocator >, std::default_delete, std::allocator > > >", + summary='"hello"', + children=[ValueCheck(name="__value_", summary='"hello"')], + ) + + valobj = self.expect_var_path( + "up_user", type="std::unique_ptr >" + ) + self.assertRegex(valobj.summary, "^User @ 0x0*[1-9a-f][0-9a-f]+$") + self.assertNotEqual(valobj.child[0].unsigned, 0) + + valobj = self.expect_var_path( + "*up_user", + type="User", + children=[ + ValueCheck(name="id", value="30"), + ValueCheck(name="name", summary='"steph"'), + ], + ) + self.assertEqual(str(valobj), '(User) *__value_ = (id = 30, name = "steph")') + + self.expect_var_path("up_user->id", type="int", value="30") + self.expect_var_path("up_user->name", type="std::string", summary='"steph"') diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp index 4ccffe2..5201b2a 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp @@ -1,13 +1,18 @@ -#include #include #include +struct User { + int id = 30; + std::string name = "steph"; +}; + int main() { std::unique_ptr up_empty; std::unique_ptr up_int = std::make_unique(10); std::unique_ptr up_str = std::make_unique("hello"); std::unique_ptr &up_int_ref = up_int; std::unique_ptr &&up_int_ref_ref = std::make_unique(10); + std::unique_ptr up_user = std::make_unique(); return 0; // break here } -- 2.7.4