xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- LibStdcppUniquePointer.cpp ----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "LibStdcpp.h"
10 
11 #include "lldb/DataFormatters/FormattersHelpers.h"
12 #include "lldb/DataFormatters/TypeSynthetic.h"
13 #include "lldb/Utility/ConstString.h"
14 #include "lldb/ValueObject/ValueObject.h"
15 
16 #include <memory>
17 #include <vector>
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 using namespace lldb_private::formatters;
22 
23 namespace {
24 
25 class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
26 public:
27   explicit LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
28 
29   llvm::Expected<uint32_t> CalculateNumChildren() override;
30 
31   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
32 
33   lldb::ChildCacheState Update() override;
34 
35   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
36 
37   bool GetSummary(Stream &stream, const TypeSummaryOptions &options);
38 
39 private:
40   // The lifetime of a ValueObject and all its derivative ValueObjects
41   // (children, clones, etc.) is managed by a ClusterManager. These
42   // objects are only destroyed when every shared pointer to any of them
43   // is destroyed, so we must not store a shared pointer to any ValueObject
44   // derived from our backend ValueObject (since we're in the same cluster).
45   ValueObject *m_ptr_obj = nullptr;
46   ValueObject* m_del_obj = nullptr;
47 
48   ValueObjectSP GetTuple();
49 };
50 
51 } // end of anonymous namespace
52 
LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)53 LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd(
54     lldb::ValueObjectSP valobj_sp)
55     : SyntheticChildrenFrontEnd(*valobj_sp) {
56   Update();
57 }
58 
GetTuple()59 ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() {
60   ValueObjectSP valobj_backend_sp = m_backend.GetSP();
61 
62   if (!valobj_backend_sp)
63     return nullptr;
64 
65   ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();
66   if (!valobj_sp)
67     return nullptr;
68 
69   ValueObjectSP obj_child_sp = valobj_sp->GetChildMemberWithName("_M_t");
70   if (!obj_child_sp)
71       return nullptr;
72 
73   ValueObjectSP obj_subchild_sp = obj_child_sp->GetChildMemberWithName("_M_t");
74 
75   // if there is a _M_t subchild, the tuple is found in the obj_subchild_sp
76   // (for libstdc++ 6.0.23).
77   if (obj_subchild_sp) {
78     return obj_subchild_sp;
79   }
80 
81   return obj_child_sp;
82 }
83 
Update()84 lldb::ChildCacheState LibStdcppUniquePtrSyntheticFrontEnd::Update() {
85   ValueObjectSP tuple_sp = GetTuple();
86 
87   if (!tuple_sp)
88     return lldb::ChildCacheState::eRefetch;
89 
90   std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(
91       LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));
92 
93   ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(0);
94   if (ptr_obj)
95     m_ptr_obj = ptr_obj->Clone(ConstString("pointer")).get();
96 
97   // Add a 'deleter' child if there was a non-empty deleter type specified.
98   //
99   // The object might have size=1 in the TypeSystem but occupies no dedicated
100   // storage due to no_unique_address, so infer the actual size from the total
101   // size of the unique_ptr class. If sizeof(unique_ptr) == sizeof(void*) then
102   // the deleter is empty and should be hidden.
103   if (llvm::expectedToOptional(tuple_sp->GetByteSize()).value_or(0) >
104       llvm::expectedToOptional(ptr_obj->GetByteSize()).value_or(0)) {
105     ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1);
106     if (del_obj)
107       m_del_obj = del_obj->Clone(ConstString("deleter")).get();
108   }
109 
110   return lldb::ChildCacheState::eRefetch;
111 }
112 
113 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx)114 LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
115   if (idx == 0 && m_ptr_obj)
116     return m_ptr_obj->GetSP();
117   if (idx == 1 && m_del_obj)
118     return m_del_obj->GetSP();
119   if (idx == 2) {
120     if (m_ptr_obj) {
121       Status status;
122       auto value_sp = m_ptr_obj->Dereference(status);
123       if (status.Success()) {
124         return value_sp;
125       }
126     }
127   }
128   return lldb::ValueObjectSP();
129 }
130 
131 llvm::Expected<uint32_t>
CalculateNumChildren()132 LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
133   if (m_del_obj)
134     return 2;
135   return 1;
136 }
137 
138 llvm::Expected<size_t>
GetIndexOfChildWithName(ConstString name)139 LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
140   if (name == "ptr" || name == "pointer")
141     return 0;
142   if (name == "del" || name == "deleter")
143     return 1;
144   if (name == "obj" || name == "object" || name == "$$dereference$$")
145     return 2;
146   return llvm::createStringError("Type has no child named '%s'",
147                                  name.AsCString());
148 }
149 
GetSummary(Stream & stream,const TypeSummaryOptions & options)150 bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary(
151     Stream &stream, const TypeSummaryOptions &options) {
152   if (!m_ptr_obj)
153     return false;
154 
155   DumpCxxSmartPtrPointerSummary(stream, *m_ptr_obj, options);
156 
157   return true;
158 }
159 
160 SyntheticChildrenFrontEnd *
LibStdcppUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)161 lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator(
162     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
163   return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp)
164                     : nullptr);
165 }
166 
LibStdcppUniquePointerSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)167 bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider(
168     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
169   LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP());
170   return formatter.GetSummary(stream, options);
171 }
172