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