xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- LibStdcpp.cpp -----------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "LibStdcpp.h"
10*f6aab3d8Srobert #include "LibCxx.h"
11061da546Spatrick 
12dda28197Spatrick #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
13061da546Spatrick #include "lldb/Core/ValueObject.h"
14061da546Spatrick #include "lldb/Core/ValueObjectConstResult.h"
15061da546Spatrick #include "lldb/DataFormatters/StringPrinter.h"
16061da546Spatrick #include "lldb/DataFormatters/VectorIterator.h"
17061da546Spatrick #include "lldb/Target/Target.h"
18061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
19061da546Spatrick #include "lldb/Utility/Endian.h"
20061da546Spatrick #include "lldb/Utility/Status.h"
21061da546Spatrick #include "lldb/Utility/Stream.h"
22*f6aab3d8Srobert #include <optional>
23061da546Spatrick 
24061da546Spatrick using namespace lldb;
25061da546Spatrick using namespace lldb_private;
26061da546Spatrick using namespace lldb_private::formatters;
27061da546Spatrick 
28061da546Spatrick namespace {
29061da546Spatrick 
30061da546Spatrick class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
31061da546Spatrick   /*
32061da546Spatrick    (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
33061da546Spatrick    std::char_traits<char>, std::allocator<char> > > >) ibeg = {
34061da546Spatrick    (_Base_ptr) _M_node = 0x0000000100103910 {
35061da546Spatrick    (std::_Rb_tree_color) _M_color = _S_black
36061da546Spatrick    (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
37061da546Spatrick    (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
38061da546Spatrick    (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
39061da546Spatrick    }
40061da546Spatrick    }
41061da546Spatrick    */
42061da546Spatrick 
43061da546Spatrick public:
44061da546Spatrick   explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
45061da546Spatrick 
46061da546Spatrick   size_t CalculateNumChildren() override;
47061da546Spatrick 
48061da546Spatrick   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
49061da546Spatrick 
50061da546Spatrick   bool Update() override;
51061da546Spatrick 
52061da546Spatrick   bool MightHaveChildren() override;
53061da546Spatrick 
54061da546Spatrick   size_t GetIndexOfChildWithName(ConstString name) override;
55061da546Spatrick 
56061da546Spatrick private:
57061da546Spatrick   ExecutionContextRef m_exe_ctx_ref;
58*f6aab3d8Srobert   lldb::addr_t m_pair_address = 0;
59061da546Spatrick   CompilerType m_pair_type;
60061da546Spatrick   lldb::ValueObjectSP m_pair_sp;
61061da546Spatrick };
62061da546Spatrick 
63061da546Spatrick class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
64061da546Spatrick public:
65061da546Spatrick   explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
66061da546Spatrick 
67061da546Spatrick   size_t CalculateNumChildren() override;
68061da546Spatrick 
69061da546Spatrick   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
70061da546Spatrick 
71061da546Spatrick   bool Update() override;
72061da546Spatrick 
73061da546Spatrick   bool MightHaveChildren() override;
74061da546Spatrick 
75061da546Spatrick   size_t GetIndexOfChildWithName(ConstString name) override;
76061da546Spatrick };
77061da546Spatrick 
78061da546Spatrick } // end of anonymous namespace
79061da546Spatrick 
LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)80061da546Spatrick LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
81061da546Spatrick     lldb::ValueObjectSP valobj_sp)
82*f6aab3d8Srobert     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),
83*f6aab3d8Srobert       m_pair_sp() {
84061da546Spatrick   if (valobj_sp)
85061da546Spatrick     Update();
86061da546Spatrick }
87061da546Spatrick 
Update()88061da546Spatrick bool LibstdcppMapIteratorSyntheticFrontEnd::Update() {
89061da546Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
90061da546Spatrick   if (!valobj_sp)
91061da546Spatrick     return false;
92061da546Spatrick 
93061da546Spatrick   TargetSP target_sp(valobj_sp->GetTargetSP());
94061da546Spatrick 
95061da546Spatrick   if (!target_sp)
96061da546Spatrick     return false;
97061da546Spatrick 
98061da546Spatrick   bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
99061da546Spatrick 
100061da546Spatrick   if (!valobj_sp)
101061da546Spatrick     return false;
102061da546Spatrick   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
103061da546Spatrick 
104061da546Spatrick   ValueObjectSP _M_node_sp(
105061da546Spatrick       valobj_sp->GetChildMemberWithName(ConstString("_M_node"), true));
106061da546Spatrick   if (!_M_node_sp)
107061da546Spatrick     return false;
108061da546Spatrick 
109061da546Spatrick   m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
110061da546Spatrick   if (m_pair_address == 0)
111061da546Spatrick     return false;
112061da546Spatrick 
113061da546Spatrick   m_pair_address += (is_64bit ? 32 : 16);
114061da546Spatrick 
115061da546Spatrick   CompilerType my_type(valobj_sp->GetCompilerType());
116061da546Spatrick   if (my_type.GetNumTemplateArguments() >= 1) {
117061da546Spatrick     CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
118061da546Spatrick     if (!pair_type)
119061da546Spatrick       return false;
120061da546Spatrick     m_pair_type = pair_type;
121061da546Spatrick   } else
122061da546Spatrick     return false;
123061da546Spatrick 
124061da546Spatrick   return true;
125061da546Spatrick }
126061da546Spatrick 
CalculateNumChildren()127061da546Spatrick size_t LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
128061da546Spatrick   return 2;
129061da546Spatrick }
130061da546Spatrick 
131061da546Spatrick lldb::ValueObjectSP
GetChildAtIndex(size_t idx)132061da546Spatrick LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
133061da546Spatrick   if (m_pair_address != 0 && m_pair_type) {
134061da546Spatrick     if (!m_pair_sp)
135061da546Spatrick       m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
136061da546Spatrick                                                m_exe_ctx_ref, m_pair_type);
137061da546Spatrick     if (m_pair_sp)
138061da546Spatrick       return m_pair_sp->GetChildAtIndex(idx, true);
139061da546Spatrick   }
140061da546Spatrick   return lldb::ValueObjectSP();
141061da546Spatrick }
142061da546Spatrick 
MightHaveChildren()143061da546Spatrick bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
144061da546Spatrick 
GetIndexOfChildWithName(ConstString name)145061da546Spatrick size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
146061da546Spatrick     ConstString name) {
147061da546Spatrick   if (name == "first")
148061da546Spatrick     return 0;
149061da546Spatrick   if (name == "second")
150061da546Spatrick     return 1;
151061da546Spatrick   return UINT32_MAX;
152061da546Spatrick }
153061da546Spatrick 
154061da546Spatrick SyntheticChildrenFrontEnd *
LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)155061da546Spatrick lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator(
156061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
157061da546Spatrick   return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
158061da546Spatrick                     : nullptr);
159061da546Spatrick }
160061da546Spatrick 
161061da546Spatrick /*
162061da546Spatrick  (lldb) fr var ibeg --ptr-depth 1
163061da546Spatrick  (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
164061da546Spatrick  ibeg = {
165061da546Spatrick  _M_current = 0x00000001001037a0 {
166061da546Spatrick  *_M_current = 1
167061da546Spatrick  }
168061da546Spatrick  }
169061da546Spatrick  */
170061da546Spatrick 
171061da546Spatrick SyntheticChildrenFrontEnd *
LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)172061da546Spatrick lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator(
173061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
174*f6aab3d8Srobert   return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
175*f6aab3d8Srobert                           valobj_sp, {ConstString("_M_current")})
176061da546Spatrick                     : nullptr);
177061da546Spatrick }
178061da546Spatrick 
179061da546Spatrick lldb_private::formatters::VectorIteratorSyntheticFrontEnd::
VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,llvm::ArrayRef<ConstString> item_names)180061da546Spatrick     VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,
181*f6aab3d8Srobert                                     llvm::ArrayRef<ConstString> item_names)
182061da546Spatrick     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
183*f6aab3d8Srobert       m_item_names(item_names), m_item_sp() {
184061da546Spatrick   if (valobj_sp)
185061da546Spatrick     Update();
186061da546Spatrick }
187061da546Spatrick 
Update()188061da546Spatrick bool VectorIteratorSyntheticFrontEnd::Update() {
189061da546Spatrick   m_item_sp.reset();
190061da546Spatrick 
191061da546Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
192061da546Spatrick   if (!valobj_sp)
193061da546Spatrick     return false;
194061da546Spatrick 
195061da546Spatrick   if (!valobj_sp)
196061da546Spatrick     return false;
197061da546Spatrick 
198*f6aab3d8Srobert   ValueObjectSP item_ptr =
199*f6aab3d8Srobert       formatters::GetChildMemberWithName(*valobj_sp, m_item_names);
200061da546Spatrick   if (!item_ptr)
201061da546Spatrick     return false;
202061da546Spatrick   if (item_ptr->GetValueAsUnsigned(0) == 0)
203061da546Spatrick     return false;
204061da546Spatrick   Status err;
205061da546Spatrick   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
206061da546Spatrick   m_item_sp = CreateValueObjectFromAddress(
207061da546Spatrick       "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
208061da546Spatrick       item_ptr->GetCompilerType().GetPointeeType());
209061da546Spatrick   if (err.Fail())
210061da546Spatrick     m_item_sp.reset();
211061da546Spatrick   return false;
212061da546Spatrick }
213061da546Spatrick 
CalculateNumChildren()214061da546Spatrick size_t VectorIteratorSyntheticFrontEnd::CalculateNumChildren() { return 1; }
215061da546Spatrick 
216061da546Spatrick lldb::ValueObjectSP
GetChildAtIndex(size_t idx)217061da546Spatrick VectorIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
218061da546Spatrick   if (idx == 0)
219061da546Spatrick     return m_item_sp;
220061da546Spatrick   return lldb::ValueObjectSP();
221061da546Spatrick }
222061da546Spatrick 
MightHaveChildren()223061da546Spatrick bool VectorIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
224061da546Spatrick 
GetIndexOfChildWithName(ConstString name)225061da546Spatrick size_t VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
226061da546Spatrick     ConstString name) {
227061da546Spatrick   if (name == "item")
228061da546Spatrick     return 0;
229061da546Spatrick   return UINT32_MAX;
230061da546Spatrick }
231061da546Spatrick 
LibStdcppStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)232061da546Spatrick bool lldb_private::formatters::LibStdcppStringSummaryProvider(
233061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
234061da546Spatrick   const bool scalar_is_load_addr = true;
235061da546Spatrick   AddressType addr_type;
236061da546Spatrick   lldb::addr_t addr_of_string =
237061da546Spatrick       valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
238061da546Spatrick   if (addr_of_string != LLDB_INVALID_ADDRESS) {
239061da546Spatrick     switch (addr_type) {
240061da546Spatrick     case eAddressTypeLoad: {
241061da546Spatrick       ProcessSP process_sp(valobj.GetProcessSP());
242061da546Spatrick       if (!process_sp)
243061da546Spatrick         return false;
244061da546Spatrick 
245061da546Spatrick       StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
246061da546Spatrick       Status error;
247061da546Spatrick       lldb::addr_t addr_of_data =
248061da546Spatrick           process_sp->ReadPointerFromMemory(addr_of_string, error);
249061da546Spatrick       if (error.Fail() || addr_of_data == 0 ||
250061da546Spatrick           addr_of_data == LLDB_INVALID_ADDRESS)
251061da546Spatrick         return false;
252061da546Spatrick       options.SetLocation(addr_of_data);
253*f6aab3d8Srobert       options.SetTargetSP(valobj.GetTargetSP());
254061da546Spatrick       options.SetStream(&stream);
255061da546Spatrick       options.SetNeedsZeroTermination(false);
256061da546Spatrick       options.SetBinaryZeroIsTerminator(true);
257061da546Spatrick       lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
258061da546Spatrick           addr_of_string + process_sp->GetAddressByteSize(), error);
259061da546Spatrick       if (error.Fail())
260061da546Spatrick         return false;
261061da546Spatrick       options.SetSourceSize(size_of_data);
262dda28197Spatrick       options.SetHasSourceSize(true);
263061da546Spatrick 
264061da546Spatrick       if (!StringPrinter::ReadStringAndDumpToStream<
265061da546Spatrick               StringPrinter::StringElementType::UTF8>(options)) {
266061da546Spatrick         stream.Printf("Summary Unavailable");
267061da546Spatrick         return true;
268061da546Spatrick       } else
269061da546Spatrick         return true;
270061da546Spatrick     } break;
271061da546Spatrick     case eAddressTypeHost:
272061da546Spatrick       break;
273061da546Spatrick     case eAddressTypeInvalid:
274061da546Spatrick     case eAddressTypeFile:
275061da546Spatrick       break;
276061da546Spatrick     }
277061da546Spatrick   }
278061da546Spatrick   return false;
279061da546Spatrick }
280061da546Spatrick 
LibStdcppWStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)281061da546Spatrick bool lldb_private::formatters::LibStdcppWStringSummaryProvider(
282061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
283061da546Spatrick   const bool scalar_is_load_addr = true;
284061da546Spatrick   AddressType addr_type;
285061da546Spatrick   lldb::addr_t addr_of_string =
286061da546Spatrick       valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
287061da546Spatrick   if (addr_of_string != LLDB_INVALID_ADDRESS) {
288061da546Spatrick     switch (addr_type) {
289061da546Spatrick     case eAddressTypeLoad: {
290061da546Spatrick       ProcessSP process_sp(valobj.GetProcessSP());
291061da546Spatrick       if (!process_sp)
292061da546Spatrick         return false;
293061da546Spatrick 
294061da546Spatrick       CompilerType wchar_compiler_type =
295061da546Spatrick           valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
296061da546Spatrick 
297061da546Spatrick       if (!wchar_compiler_type)
298061da546Spatrick         return false;
299061da546Spatrick 
300061da546Spatrick       // Safe to pass nullptr for exe_scope here.
301*f6aab3d8Srobert       std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
302061da546Spatrick       if (!size)
303061da546Spatrick         return false;
304061da546Spatrick       const uint32_t wchar_size = *size;
305061da546Spatrick 
306061da546Spatrick       StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
307061da546Spatrick       Status error;
308061da546Spatrick       lldb::addr_t addr_of_data =
309061da546Spatrick           process_sp->ReadPointerFromMemory(addr_of_string, error);
310061da546Spatrick       if (error.Fail() || addr_of_data == 0 ||
311061da546Spatrick           addr_of_data == LLDB_INVALID_ADDRESS)
312061da546Spatrick         return false;
313061da546Spatrick       options.SetLocation(addr_of_data);
314*f6aab3d8Srobert       options.SetTargetSP(valobj.GetTargetSP());
315061da546Spatrick       options.SetStream(&stream);
316061da546Spatrick       options.SetNeedsZeroTermination(false);
317061da546Spatrick       options.SetBinaryZeroIsTerminator(false);
318061da546Spatrick       lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
319061da546Spatrick           addr_of_string + process_sp->GetAddressByteSize(), error);
320061da546Spatrick       if (error.Fail())
321061da546Spatrick         return false;
322061da546Spatrick       options.SetSourceSize(size_of_data);
323dda28197Spatrick       options.SetHasSourceSize(true);
324061da546Spatrick       options.SetPrefixToken("L");
325061da546Spatrick 
326061da546Spatrick       switch (wchar_size) {
327061da546Spatrick       case 8:
328061da546Spatrick         return StringPrinter::ReadStringAndDumpToStream<
329061da546Spatrick             StringPrinter::StringElementType::UTF8>(options);
330061da546Spatrick       case 16:
331061da546Spatrick         return StringPrinter::ReadStringAndDumpToStream<
332061da546Spatrick             StringPrinter::StringElementType::UTF16>(options);
333061da546Spatrick       case 32:
334061da546Spatrick         return StringPrinter::ReadStringAndDumpToStream<
335061da546Spatrick             StringPrinter::StringElementType::UTF32>(options);
336061da546Spatrick       default:
337061da546Spatrick         stream.Printf("size for wchar_t is not valid");
338061da546Spatrick         return true;
339061da546Spatrick       }
340061da546Spatrick       return true;
341061da546Spatrick     } break;
342061da546Spatrick     case eAddressTypeHost:
343061da546Spatrick       break;
344061da546Spatrick     case eAddressTypeInvalid:
345061da546Spatrick     case eAddressTypeFile:
346061da546Spatrick       break;
347061da546Spatrick     }
348061da546Spatrick   }
349061da546Spatrick   return false;
350061da546Spatrick }
351061da546Spatrick 
LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)352061da546Spatrick LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
353061da546Spatrick     lldb::ValueObjectSP valobj_sp)
354061da546Spatrick     : SyntheticChildrenFrontEnd(*valobj_sp) {
355061da546Spatrick   if (valobj_sp)
356061da546Spatrick     Update();
357061da546Spatrick }
358061da546Spatrick 
CalculateNumChildren()359061da546Spatrick size_t LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() { return 1; }
360061da546Spatrick 
361061da546Spatrick lldb::ValueObjectSP
GetChildAtIndex(size_t idx)362061da546Spatrick LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
363061da546Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
364061da546Spatrick   if (!valobj_sp)
365061da546Spatrick     return lldb::ValueObjectSP();
366061da546Spatrick 
367061da546Spatrick   if (idx == 0)
368061da546Spatrick     return valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true);
369061da546Spatrick   else
370061da546Spatrick     return lldb::ValueObjectSP();
371061da546Spatrick }
372061da546Spatrick 
Update()373061da546Spatrick bool LibStdcppSharedPtrSyntheticFrontEnd::Update() { return false; }
374061da546Spatrick 
MightHaveChildren()375061da546Spatrick bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; }
376061da546Spatrick 
GetIndexOfChildWithName(ConstString name)377061da546Spatrick size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(
378061da546Spatrick     ConstString name) {
379061da546Spatrick   if (name == "_M_ptr")
380061da546Spatrick     return 0;
381061da546Spatrick   return UINT32_MAX;
382061da546Spatrick }
383061da546Spatrick 
384061da546Spatrick SyntheticChildrenFrontEnd *
LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)385061da546Spatrick lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(
386061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
387061da546Spatrick   return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
388061da546Spatrick                     : nullptr);
389061da546Spatrick }
390061da546Spatrick 
LibStdcppSmartPointerSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)391061da546Spatrick bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(
392061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
393061da546Spatrick   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
394061da546Spatrick   if (!valobj_sp)
395061da546Spatrick     return false;
396061da546Spatrick 
397061da546Spatrick   ValueObjectSP ptr_sp(
398061da546Spatrick       valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true));
399061da546Spatrick   if (!ptr_sp)
400061da546Spatrick     return false;
401061da546Spatrick 
402061da546Spatrick   ValueObjectSP usecount_sp(valobj_sp->GetChildAtNamePath(
403061da546Spatrick       {ConstString("_M_refcount"), ConstString("_M_pi"),
404061da546Spatrick        ConstString("_M_use_count")}));
405061da546Spatrick   if (!usecount_sp)
406061da546Spatrick     return false;
407061da546Spatrick 
408061da546Spatrick   if (ptr_sp->GetValueAsUnsigned(0) == 0 ||
409061da546Spatrick       usecount_sp->GetValueAsUnsigned(0) == 0) {
410061da546Spatrick     stream.Printf("nullptr");
411061da546Spatrick     return true;
412061da546Spatrick   }
413061da546Spatrick 
414061da546Spatrick   Status error;
415061da546Spatrick   ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
416061da546Spatrick   if (pointee_sp && error.Success()) {
417061da546Spatrick     if (pointee_sp->DumpPrintableRepresentation(
418061da546Spatrick             stream, ValueObject::eValueObjectRepresentationStyleSummary,
419061da546Spatrick             lldb::eFormatInvalid,
420061da546Spatrick             ValueObject::PrintableRepresentationSpecialCases::eDisable,
421061da546Spatrick             false)) {
422061da546Spatrick       return true;
423061da546Spatrick     }
424061da546Spatrick   }
425061da546Spatrick 
426061da546Spatrick   stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
427061da546Spatrick   return true;
428061da546Spatrick }
429