xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- MsvcStlSmartPointer.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 "Generic.h"
10 #include "MsvcStl.h"
11 
12 #include "lldb/DataFormatters/FormattersHelpers.h"
13 #include "lldb/DataFormatters/TypeSynthetic.h"
14 
15 using namespace lldb;
16 
IsMsvcStlSmartPointer(ValueObject & valobj)17 bool lldb_private::formatters::IsMsvcStlSmartPointer(ValueObject &valobj) {
18   if (auto valobj_sp = valobj.GetNonSyntheticValue())
19     return valobj_sp->GetChildMemberWithName("_Ptr") != nullptr;
20 
21   return false;
22 }
23 
MsvcStlSmartPointerSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)24 bool lldb_private::formatters::MsvcStlSmartPointerSummaryProvider(
25     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
26   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
27   if (!valobj_sp)
28     return false;
29 
30   ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_Ptr"));
31   ValueObjectSP ctrl_sp(valobj_sp->GetChildMemberWithName("_Rep"));
32   if (!ctrl_sp || !ptr_sp)
33     return false;
34 
35   DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);
36 
37   bool success;
38   uint64_t ctrl_addr = ctrl_sp->GetValueAsUnsigned(0, &success);
39   // Empty control field (expired)
40   if (!success || ctrl_addr == 0)
41     return true;
42 
43   uint64_t uses = 0;
44   if (auto uses_sp = ctrl_sp->GetChildMemberWithName("_Uses")) {
45     bool success;
46     uses = uses_sp->GetValueAsUnsigned(0, &success);
47     if (!success)
48       return false;
49 
50     stream.Printf(" strong=%" PRIu64, uses);
51   }
52 
53   // _Weaks is the number of weak references - (_Uses != 0).
54   if (auto weak_count_sp = ctrl_sp->GetChildMemberWithName("_Weaks")) {
55     bool success;
56     uint64_t count = weak_count_sp->GetValueAsUnsigned(0, &success);
57     if (!success)
58       return false;
59 
60     stream.Printf(" weak=%" PRIu64, count - (uses != 0));
61   }
62 
63   return true;
64 }
65 
66 namespace lldb_private {
67 namespace formatters {
68 
69 class MsvcStlSmartPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
70 public:
71   MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
72 
73   llvm::Expected<uint32_t> CalculateNumChildren() override;
74 
75   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
76 
77   lldb::ChildCacheState Update() override;
78 
79   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
80 
81   ~MsvcStlSmartPointerSyntheticFrontEnd() override;
82 
83 private:
84   ValueObject *m_ptr_obj = nullptr;
85 };
86 
87 class MsvcStlUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
88 public:
89   MsvcStlUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
90 
91   llvm::Expected<uint32_t> CalculateNumChildren() override;
92 
93   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
94 
95   lldb::ChildCacheState Update() override;
96 
97   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
98 
99 private:
100   lldb::ValueObjectSP m_value_ptr_sp;
101   lldb::ValueObjectSP m_deleter_sp;
102 };
103 
104 } // namespace formatters
105 } // namespace lldb_private
106 
107 lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)108     MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
109     : SyntheticChildrenFrontEnd(*valobj_sp) {
110   if (valobj_sp)
111     Update();
112 }
113 
114 llvm::Expected<uint32_t> lldb_private::formatters::
CalculateNumChildren()115     MsvcStlSmartPointerSyntheticFrontEnd::CalculateNumChildren() {
116   return (m_ptr_obj ? 1 : 0);
117 }
118 
119 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx)120 lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::GetChildAtIndex(
121     uint32_t idx) {
122   if (!m_ptr_obj)
123     return lldb::ValueObjectSP();
124 
125   ValueObjectSP valobj_sp = m_backend.GetSP();
126   if (!valobj_sp)
127     return lldb::ValueObjectSP();
128 
129   if (idx == 0)
130     return m_ptr_obj->GetSP();
131 
132   if (idx == 1) {
133     Status status;
134     ValueObjectSP value_sp = m_ptr_obj->Dereference(status);
135     if (status.Success())
136       return value_sp;
137   }
138 
139   return lldb::ValueObjectSP();
140 }
141 
142 lldb::ChildCacheState
Update()143 lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::Update() {
144   m_ptr_obj = nullptr;
145 
146   ValueObjectSP valobj_sp = m_backend.GetSP();
147   if (!valobj_sp)
148     return lldb::ChildCacheState::eRefetch;
149 
150   auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_Ptr");
151   if (!ptr_obj_sp)
152     return lldb::ChildCacheState::eRefetch;
153 
154   auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp);
155   if (!cast_ptr_sp)
156     return lldb::ChildCacheState::eRefetch;
157 
158   m_ptr_obj = cast_ptr_sp->Clone(ConstString("pointer")).get();
159   return lldb::ChildCacheState::eRefetch;
160 }
161 
162 llvm::Expected<size_t>
163 lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)164     GetIndexOfChildWithName(ConstString name) {
165   if (name == "pointer")
166     return 0;
167 
168   if (name == "object" || name == "$$dereference$$")
169     return 1;
170 
171   return llvm::createStringError("Type has no child named '%s'",
172                                  name.AsCString());
173 }
174 
175 lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
176     ~MsvcStlSmartPointerSyntheticFrontEnd() = default;
177 
178 lldb_private::SyntheticChildrenFrontEnd *
MsvcStlSmartPointerSyntheticFrontEndCreator(lldb::ValueObjectSP valobj_sp)179 lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEndCreator(
180     lldb::ValueObjectSP valobj_sp) {
181   return new MsvcStlSmartPointerSyntheticFrontEnd(valobj_sp);
182 }
183 
IsMsvcStlUniquePtr(ValueObject & valobj)184 bool lldb_private::formatters::IsMsvcStlUniquePtr(ValueObject &valobj) {
185   if (auto valobj_sp = valobj.GetNonSyntheticValue())
186     return valobj_sp->GetChildMemberWithName("_Mypair") != nullptr;
187 
188   return false;
189 }
190 
MsvcStlUniquePtrSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)191 bool lldb_private::formatters::MsvcStlUniquePtrSummaryProvider(
192     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
193   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
194   if (!valobj_sp)
195     return false;
196 
197   ValueObjectSP ptr_sp(valobj_sp->GetChildAtNamePath({"_Mypair", "_Myval2"}));
198   if (!ptr_sp)
199     return false;
200 
201   DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);
202 
203   return true;
204 }
205 
206 lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::
MsvcStlUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)207     MsvcStlUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
208     : SyntheticChildrenFrontEnd(*valobj_sp) {
209   if (valobj_sp)
210     Update();
211 }
212 
213 llvm::Expected<uint32_t> lldb_private::formatters::
CalculateNumChildren()214     MsvcStlUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
215   if (m_value_ptr_sp)
216     return m_deleter_sp ? 2 : 1;
217   return 0;
218 }
219 
220 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx)221 lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::GetChildAtIndex(
222     uint32_t idx) {
223   if (!m_value_ptr_sp)
224     return lldb::ValueObjectSP();
225 
226   if (idx == 0)
227     return m_value_ptr_sp;
228 
229   if (idx == 1)
230     return m_deleter_sp;
231 
232   if (idx == 2) {
233     Status status;
234     auto value_sp = m_value_ptr_sp->Dereference(status);
235     if (status.Success()) {
236       return value_sp;
237     }
238   }
239 
240   return lldb::ValueObjectSP();
241 }
242 
243 lldb::ChildCacheState
Update()244 lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::Update() {
245   ValueObjectSP valobj_sp = m_backend.GetSP();
246   if (!valobj_sp)
247     return lldb::ChildCacheState::eRefetch;
248 
249   ValueObjectSP pair_sp = valobj_sp->GetChildMemberWithName("_Mypair");
250   if (!pair_sp)
251     return lldb::ChildCacheState::eRefetch;
252 
253   if (auto value_ptr_sp = pair_sp->GetChildMemberWithName("_Myval2"))
254     m_value_ptr_sp = value_ptr_sp->Clone(ConstString("pointer"));
255 
256   // Only present if the deleter is non-empty
257   if (auto deleter_sp = pair_sp->GetChildMemberWithName("_Myval1"))
258     m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
259 
260   return lldb::ChildCacheState::eRefetch;
261 }
262 
263 llvm::Expected<size_t>
264 lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)265     GetIndexOfChildWithName(ConstString name) {
266   if (name == "pointer")
267     return 0;
268   if (name == "deleter")
269     return 1;
270   if (name == "obj" || name == "object" || name == "$$dereference$$")
271     return 2;
272   return llvm::createStringError("Type has no child named '%s'",
273                                  name.AsCString());
274 }
275 
276 lldb_private::SyntheticChildrenFrontEnd *
MsvcStlUniquePtrSyntheticFrontEndCreator(lldb::ValueObjectSP valobj_sp)277 lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEndCreator(
278     lldb::ValueObjectSP valobj_sp) {
279   return new MsvcStlUniquePtrSyntheticFrontEnd(valobj_sp);
280 }
281