From: Michael Buch Date: Tue, 23 May 2023 23:01:47 +0000 (+0100) Subject: [lldb][DataFormatter] Add dereference support to libstdcpp std::shared_ptr formatter X-Git-Tag: upstream/17.0.6~7403 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=44bb442fd5be3860e7819cb216621b5ea59970c3;p=platform%2Fupstream%2Fllvm.git [lldb][DataFormatter] Add dereference support to libstdcpp std::shared_ptr formatter This mimicks the implementation of the libstdcpp std::unique_ptr formatter. This has been attempted several years ago in `0789722d85cf1f1fdbe2ffb2245ea0ba034a9f94` but was reverted in `e7dd3972094c2f2fb42dc9d4d5344e54a431e2ce`. The difference to the original patch is that we now maintain a `$$dereference$$` member and we only store weak pointers to the other children inside the synthetic frontend. This is what the libc++ formatters do to prevent the recursion mentioned in the revert commit. --- diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index c7f1c79..bd129d2 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -73,6 +73,15 @@ public: bool MightHaveChildren() override; size_t GetIndexOfChildWithName(ConstString name) override; +private: + + // The lifetime of a ValueObject and all its derivative ValueObjects + // (children, clones, etc.) is managed by a ClusterManager. These + // objects are only destroyed when every shared pointer to any of them + // is destroyed, so we must not store a shared pointer to any ValueObject + // derived from our backend ValueObject (since we're in the same cluster). + ValueObject* m_ptr_obj = nullptr; // Underlying pointer (held, not owned) + ValueObject* m_obj_obj = nullptr; // Underlying object (held, not owned) }; } // end of anonymous namespace @@ -367,24 +376,48 @@ 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(); + return m_ptr_obj->GetSP(); + if (idx == 1) + return m_obj_obj->GetSP(); + + return lldb::ValueObjectSP(); } -bool LibStdcppSharedPtrSyntheticFrontEnd::Update() { return false; } +bool LibStdcppSharedPtrSyntheticFrontEnd::Update() { + auto backend = m_backend.GetSP(); + if (!backend) + return false; + + auto valobj_sp = backend->GetNonSyntheticValue(); + if (!valobj_sp) + return false; + + auto ptr_obj_sp = valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true); + if (!ptr_obj_sp) + return false; + + m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get(); + + if (m_ptr_obj) { + Status error; + ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); + if (error.Success()) { + m_obj_obj = obj_obj->Clone(ConstString("object")).get(); + } + } + + return false; +} bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; } size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName( ConstString name) { - if (name == "_M_ptr") + if (name == "pointer") return 0; + if (name == "object" || name == "$$dereference$$") + return 1; return UINT32_MAX; } diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/TestDataFormatterStdSmartPtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/TestDataFormatterStdSmartPtr.py index 3d37af3..13bcb68 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/TestDataFormatterStdSmartPtr.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/TestDataFormatterStdSmartPtr.py @@ -33,6 +33,13 @@ class StdSmartPtrDataFormatterTestCase(TestBase): self.expect("frame variable iwp", substrs=['iwp = 123']) self.expect("frame variable swp", substrs=['swp = "foobar"']) + self.expect("frame variable *nsp", substrs=['*nsp = ']) + self.expect("frame variable *isp", substrs=['*isp = 123']) + self.expect("frame variable *ssp", substrs=['*ssp = "foobar"']) + self.expect("frame variable *fsp", substrs=['*fsp = (mem = 5)']) + + self.expect("frame variable fsp->mem", substrs=['(int) fsp->mem = 5']) + self.runCmd("continue") self.expect("frame variable nsp", substrs=['nsp = nullptr']) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/main.cpp index 7ba5087..6e4b869 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/main.cpp @@ -1,12 +1,17 @@ #include #include +struct Foo { + int mem = 5; +}; + int main() { std::shared_ptr nsp; std::shared_ptr isp(new int{123}); std::shared_ptr ssp = std::make_shared("foobar"); + std::shared_ptr fsp = std::make_shared(); std::weak_ptr nwp; std::weak_ptr iwp = isp; @@ -15,6 +20,7 @@ main() nsp.reset(); // Set break point at this line. isp.reset(); ssp.reset(); + fsp.reset(); return 0; // Set break point at this line. }