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
15using namespace lldb;
16
17bool lldb_private::formatters::IsMsvcStlSmartPointer(ValueObject &valobj) {
18 if (auto valobj_sp = valobj.GetNonSyntheticValue())
19 return valobj_sp->GetChildMemberWithName(name: "_Ptr") != nullptr;
20
21 return false;
22}
23
24bool 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(name: "_Ptr"));
31 ValueObjectSP ctrl_sp(valobj_sp->GetChildMemberWithName(name: "_Rep"));
32 if (!ctrl_sp || !ptr_sp)
33 return false;
34
35 DumpCxxSmartPtrPointerSummary(stream, ptr&: *ptr_sp, options);
36
37 bool success;
38 uint64_t ctrl_addr = ctrl_sp->GetValueAsUnsigned(fail_value: 0, success: &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(name: "_Uses")) {
45 bool success;
46 uses = uses_sp->GetValueAsUnsigned(fail_value: 0, success: &success);
47 if (!success)
48 return false;
49
50 stream.Printf(format: " strong=%" PRIu64, uses);
51 }
52
53 // _Weaks is the number of weak references - (_Uses != 0).
54 if (auto weak_count_sp = ctrl_sp->GetChildMemberWithName(name: "_Weaks")) {
55 bool success;
56 uint64_t count = weak_count_sp->GetValueAsUnsigned(fail_value: 0, success: &success);
57 if (!success)
58 return false;
59
60 stream.Printf(format: " weak=%" PRIu64, count - (uses != 0));
61 }
62
63 return true;
64}
65
66namespace lldb_private {
67namespace formatters {
68
69class MsvcStlSmartPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
70public:
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
83private:
84 ValueObject *m_ptr_obj = nullptr;
85};
86
87class MsvcStlUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
88public:
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
99private:
100 lldb::ValueObjectSP m_value_ptr_sp;
101 lldb::ValueObjectSP m_deleter_sp;
102};
103
104} // namespace formatters
105} // namespace lldb_private
106
107lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
108 MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
109 : SyntheticChildrenFrontEnd(*valobj_sp) {
110 if (valobj_sp)
111 Update();
112}
113
114llvm::Expected<uint32_t> lldb_private::formatters::
115 MsvcStlSmartPointerSyntheticFrontEnd::CalculateNumChildren() {
116 return (m_ptr_obj ? 1 : 0);
117}
118
119lldb::ValueObjectSP
120lldb_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(error&: status);
135 if (status.Success())
136 return value_sp;
137 }
138
139 return lldb::ValueObjectSP();
140}
141
142lldb::ChildCacheState
143lldb_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(name: "_Ptr");
151 if (!ptr_obj_sp)
152 return lldb::ChildCacheState::eRefetch;
153
154 auto cast_ptr_sp = GetDesugaredSmartPointerValue(ptr&: *ptr_obj_sp, container&: *valobj_sp);
155 if (!cast_ptr_sp)
156 return lldb::ChildCacheState::eRefetch;
157
158 m_ptr_obj = cast_ptr_sp->Clone(new_name: ConstString("pointer")).get();
159 return lldb::ChildCacheState::eRefetch;
160}
161
162llvm::Expected<size_t>
163lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
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(Fmt: "Type has no child named '%s'",
172 Vals: name.AsCString());
173}
174
175lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
176 ~MsvcStlSmartPointerSyntheticFrontEnd() = default;
177
178lldb_private::SyntheticChildrenFrontEnd *
179lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEndCreator(
180 lldb::ValueObjectSP valobj_sp) {
181 return new MsvcStlSmartPointerSyntheticFrontEnd(valobj_sp);
182}
183
184bool lldb_private::formatters::IsMsvcStlUniquePtr(ValueObject &valobj) {
185 if (auto valobj_sp = valobj.GetNonSyntheticValue())
186 return valobj_sp->GetChildMemberWithName(name: "_Mypair") != nullptr;
187
188 return false;
189}
190
191bool 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(names: {"_Mypair", "_Myval2"}));
198 if (!ptr_sp)
199 return false;
200
201 DumpCxxSmartPtrPointerSummary(stream, ptr&: *ptr_sp, options);
202
203 return true;
204}
205
206lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::
207 MsvcStlUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
208 : SyntheticChildrenFrontEnd(*valobj_sp) {
209 if (valobj_sp)
210 Update();
211}
212
213llvm::Expected<uint32_t> lldb_private::formatters::
214 MsvcStlUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
215 if (m_value_ptr_sp)
216 return m_deleter_sp ? 2 : 1;
217 return 0;
218}
219
220lldb::ValueObjectSP
221lldb_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(error&: status);
235 if (status.Success()) {
236 return value_sp;
237 }
238 }
239
240 return lldb::ValueObjectSP();
241}
242
243lldb::ChildCacheState
244lldb_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(name: "_Mypair");
250 if (!pair_sp)
251 return lldb::ChildCacheState::eRefetch;
252
253 if (auto value_ptr_sp = pair_sp->GetChildMemberWithName(name: "_Myval2"))
254 m_value_ptr_sp = value_ptr_sp->Clone(new_name: ConstString("pointer"));
255
256 // Only present if the deleter is non-empty
257 if (auto deleter_sp = pair_sp->GetChildMemberWithName(name: "_Myval1"))
258 m_deleter_sp = deleter_sp->Clone(new_name: ConstString("deleter"));
259
260 return lldb::ChildCacheState::eRefetch;
261}
262
263llvm::Expected<size_t>
264lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::
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(Fmt: "Type has no child named '%s'",
273 Vals: name.AsCString());
274}
275
276lldb_private::SyntheticChildrenFrontEnd *
277lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEndCreator(
278 lldb::ValueObjectSP valobj_sp) {
279 return new MsvcStlUniquePtrSyntheticFrontEnd(valobj_sp);
280}
281

source code of lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp