xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
1*061da546Spatrick //===-- LibStdcpp.cpp -------------------------------------------*- C++ -*-===//
2*061da546Spatrick //
3*061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*061da546Spatrick //
7*061da546Spatrick //===----------------------------------------------------------------------===//
8*061da546Spatrick 
9*061da546Spatrick #include "LibStdcpp.h"
10*061da546Spatrick 
11*061da546Spatrick #include "lldb/Core/ValueObject.h"
12*061da546Spatrick #include "lldb/Core/ValueObjectConstResult.h"
13*061da546Spatrick #include "lldb/DataFormatters/StringPrinter.h"
14*061da546Spatrick #include "lldb/DataFormatters/VectorIterator.h"
15*061da546Spatrick #include "lldb/Symbol/ClangASTContext.h"
16*061da546Spatrick #include "lldb/Target/Target.h"
17*061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
18*061da546Spatrick #include "lldb/Utility/Endian.h"
19*061da546Spatrick #include "lldb/Utility/Status.h"
20*061da546Spatrick #include "lldb/Utility/Stream.h"
21*061da546Spatrick 
22*061da546Spatrick using namespace lldb;
23*061da546Spatrick using namespace lldb_private;
24*061da546Spatrick using namespace lldb_private::formatters;
25*061da546Spatrick 
26*061da546Spatrick namespace {
27*061da546Spatrick 
28*061da546Spatrick class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
29*061da546Spatrick   /*
30*061da546Spatrick    (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
31*061da546Spatrick    std::char_traits<char>, std::allocator<char> > > >) ibeg = {
32*061da546Spatrick    (_Base_ptr) _M_node = 0x0000000100103910 {
33*061da546Spatrick    (std::_Rb_tree_color) _M_color = _S_black
34*061da546Spatrick    (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
35*061da546Spatrick    (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
36*061da546Spatrick    (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
37*061da546Spatrick    }
38*061da546Spatrick    }
39*061da546Spatrick    */
40*061da546Spatrick 
41*061da546Spatrick public:
42*061da546Spatrick   explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
43*061da546Spatrick 
44*061da546Spatrick   size_t CalculateNumChildren() override;
45*061da546Spatrick 
46*061da546Spatrick   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
47*061da546Spatrick 
48*061da546Spatrick   bool Update() override;
49*061da546Spatrick 
50*061da546Spatrick   bool MightHaveChildren() override;
51*061da546Spatrick 
52*061da546Spatrick   size_t GetIndexOfChildWithName(ConstString name) override;
53*061da546Spatrick 
54*061da546Spatrick private:
55*061da546Spatrick   ExecutionContextRef m_exe_ctx_ref;
56*061da546Spatrick   lldb::addr_t m_pair_address;
57*061da546Spatrick   CompilerType m_pair_type;
58*061da546Spatrick   lldb::ValueObjectSP m_pair_sp;
59*061da546Spatrick };
60*061da546Spatrick 
61*061da546Spatrick class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
62*061da546Spatrick public:
63*061da546Spatrick   explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
64*061da546Spatrick 
65*061da546Spatrick   size_t CalculateNumChildren() override;
66*061da546Spatrick 
67*061da546Spatrick   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
68*061da546Spatrick 
69*061da546Spatrick   bool Update() override;
70*061da546Spatrick 
71*061da546Spatrick   bool MightHaveChildren() override;
72*061da546Spatrick 
73*061da546Spatrick   size_t GetIndexOfChildWithName(ConstString name) override;
74*061da546Spatrick };
75*061da546Spatrick 
76*061da546Spatrick } // end of anonymous namespace
77*061da546Spatrick 
78*061da546Spatrick LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
79*061da546Spatrick     lldb::ValueObjectSP valobj_sp)
80*061da546Spatrick     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_address(0),
81*061da546Spatrick       m_pair_type(), m_pair_sp() {
82*061da546Spatrick   if (valobj_sp)
83*061da546Spatrick     Update();
84*061da546Spatrick }
85*061da546Spatrick 
86*061da546Spatrick bool LibstdcppMapIteratorSyntheticFrontEnd::Update() {
87*061da546Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
88*061da546Spatrick   if (!valobj_sp)
89*061da546Spatrick     return false;
90*061da546Spatrick 
91*061da546Spatrick   TargetSP target_sp(valobj_sp->GetTargetSP());
92*061da546Spatrick 
93*061da546Spatrick   if (!target_sp)
94*061da546Spatrick     return false;
95*061da546Spatrick 
96*061da546Spatrick   bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
97*061da546Spatrick 
98*061da546Spatrick   if (!valobj_sp)
99*061da546Spatrick     return false;
100*061da546Spatrick   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
101*061da546Spatrick 
102*061da546Spatrick   ValueObjectSP _M_node_sp(
103*061da546Spatrick       valobj_sp->GetChildMemberWithName(ConstString("_M_node"), true));
104*061da546Spatrick   if (!_M_node_sp)
105*061da546Spatrick     return false;
106*061da546Spatrick 
107*061da546Spatrick   m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
108*061da546Spatrick   if (m_pair_address == 0)
109*061da546Spatrick     return false;
110*061da546Spatrick 
111*061da546Spatrick   m_pair_address += (is_64bit ? 32 : 16);
112*061da546Spatrick 
113*061da546Spatrick   CompilerType my_type(valobj_sp->GetCompilerType());
114*061da546Spatrick   if (my_type.GetNumTemplateArguments() >= 1) {
115*061da546Spatrick     CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
116*061da546Spatrick     if (!pair_type)
117*061da546Spatrick       return false;
118*061da546Spatrick     m_pair_type = pair_type;
119*061da546Spatrick   } else
120*061da546Spatrick     return false;
121*061da546Spatrick 
122*061da546Spatrick   return true;
123*061da546Spatrick }
124*061da546Spatrick 
125*061da546Spatrick size_t LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
126*061da546Spatrick   return 2;
127*061da546Spatrick }
128*061da546Spatrick 
129*061da546Spatrick lldb::ValueObjectSP
130*061da546Spatrick LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
131*061da546Spatrick   if (m_pair_address != 0 && m_pair_type) {
132*061da546Spatrick     if (!m_pair_sp)
133*061da546Spatrick       m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
134*061da546Spatrick                                                m_exe_ctx_ref, m_pair_type);
135*061da546Spatrick     if (m_pair_sp)
136*061da546Spatrick       return m_pair_sp->GetChildAtIndex(idx, true);
137*061da546Spatrick   }
138*061da546Spatrick   return lldb::ValueObjectSP();
139*061da546Spatrick }
140*061da546Spatrick 
141*061da546Spatrick bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
142*061da546Spatrick 
143*061da546Spatrick size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
144*061da546Spatrick     ConstString name) {
145*061da546Spatrick   if (name == "first")
146*061da546Spatrick     return 0;
147*061da546Spatrick   if (name == "second")
148*061da546Spatrick     return 1;
149*061da546Spatrick   return UINT32_MAX;
150*061da546Spatrick }
151*061da546Spatrick 
152*061da546Spatrick SyntheticChildrenFrontEnd *
153*061da546Spatrick lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator(
154*061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
155*061da546Spatrick   return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
156*061da546Spatrick                     : nullptr);
157*061da546Spatrick }
158*061da546Spatrick 
159*061da546Spatrick /*
160*061da546Spatrick  (lldb) fr var ibeg --ptr-depth 1
161*061da546Spatrick  (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
162*061da546Spatrick  ibeg = {
163*061da546Spatrick  _M_current = 0x00000001001037a0 {
164*061da546Spatrick  *_M_current = 1
165*061da546Spatrick  }
166*061da546Spatrick  }
167*061da546Spatrick  */
168*061da546Spatrick 
169*061da546Spatrick SyntheticChildrenFrontEnd *
170*061da546Spatrick lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator(
171*061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
172*061da546Spatrick   static ConstString g_item_name;
173*061da546Spatrick   if (!g_item_name)
174*061da546Spatrick     g_item_name.SetCString("_M_current");
175*061da546Spatrick   return (valobj_sp
176*061da546Spatrick               ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name)
177*061da546Spatrick               : nullptr);
178*061da546Spatrick }
179*061da546Spatrick 
180*061da546Spatrick lldb_private::formatters::VectorIteratorSyntheticFrontEnd::
181*061da546Spatrick     VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,
182*061da546Spatrick                                     ConstString item_name)
183*061da546Spatrick     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
184*061da546Spatrick       m_item_name(item_name), m_item_sp() {
185*061da546Spatrick   if (valobj_sp)
186*061da546Spatrick     Update();
187*061da546Spatrick }
188*061da546Spatrick 
189*061da546Spatrick bool VectorIteratorSyntheticFrontEnd::Update() {
190*061da546Spatrick   m_item_sp.reset();
191*061da546Spatrick 
192*061da546Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
193*061da546Spatrick   if (!valobj_sp)
194*061da546Spatrick     return false;
195*061da546Spatrick 
196*061da546Spatrick   if (!valobj_sp)
197*061da546Spatrick     return false;
198*061da546Spatrick 
199*061da546Spatrick   ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name, true));
200*061da546Spatrick   if (!item_ptr)
201*061da546Spatrick     return false;
202*061da546Spatrick   if (item_ptr->GetValueAsUnsigned(0) == 0)
203*061da546Spatrick     return false;
204*061da546Spatrick   Status err;
205*061da546Spatrick   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
206*061da546Spatrick   m_item_sp = CreateValueObjectFromAddress(
207*061da546Spatrick       "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
208*061da546Spatrick       item_ptr->GetCompilerType().GetPointeeType());
209*061da546Spatrick   if (err.Fail())
210*061da546Spatrick     m_item_sp.reset();
211*061da546Spatrick   return false;
212*061da546Spatrick }
213*061da546Spatrick 
214*061da546Spatrick size_t VectorIteratorSyntheticFrontEnd::CalculateNumChildren() { return 1; }
215*061da546Spatrick 
216*061da546Spatrick lldb::ValueObjectSP
217*061da546Spatrick VectorIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
218*061da546Spatrick   if (idx == 0)
219*061da546Spatrick     return m_item_sp;
220*061da546Spatrick   return lldb::ValueObjectSP();
221*061da546Spatrick }
222*061da546Spatrick 
223*061da546Spatrick bool VectorIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
224*061da546Spatrick 
225*061da546Spatrick size_t VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
226*061da546Spatrick     ConstString name) {
227*061da546Spatrick   if (name == "item")
228*061da546Spatrick     return 0;
229*061da546Spatrick   return UINT32_MAX;
230*061da546Spatrick }
231*061da546Spatrick 
232*061da546Spatrick bool lldb_private::formatters::LibStdcppStringSummaryProvider(
233*061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
234*061da546Spatrick   const bool scalar_is_load_addr = true;
235*061da546Spatrick   AddressType addr_type;
236*061da546Spatrick   lldb::addr_t addr_of_string =
237*061da546Spatrick       valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
238*061da546Spatrick   if (addr_of_string != LLDB_INVALID_ADDRESS) {
239*061da546Spatrick     switch (addr_type) {
240*061da546Spatrick     case eAddressTypeLoad: {
241*061da546Spatrick       ProcessSP process_sp(valobj.GetProcessSP());
242*061da546Spatrick       if (!process_sp)
243*061da546Spatrick         return false;
244*061da546Spatrick 
245*061da546Spatrick       StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
246*061da546Spatrick       Status error;
247*061da546Spatrick       lldb::addr_t addr_of_data =
248*061da546Spatrick           process_sp->ReadPointerFromMemory(addr_of_string, error);
249*061da546Spatrick       if (error.Fail() || addr_of_data == 0 ||
250*061da546Spatrick           addr_of_data == LLDB_INVALID_ADDRESS)
251*061da546Spatrick         return false;
252*061da546Spatrick       options.SetLocation(addr_of_data);
253*061da546Spatrick       options.SetProcessSP(process_sp);
254*061da546Spatrick       options.SetStream(&stream);
255*061da546Spatrick       options.SetNeedsZeroTermination(false);
256*061da546Spatrick       options.SetBinaryZeroIsTerminator(true);
257*061da546Spatrick       lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
258*061da546Spatrick           addr_of_string + process_sp->GetAddressByteSize(), error);
259*061da546Spatrick       if (error.Fail())
260*061da546Spatrick         return false;
261*061da546Spatrick       options.SetSourceSize(size_of_data);
262*061da546Spatrick 
263*061da546Spatrick       if (!StringPrinter::ReadStringAndDumpToStream<
264*061da546Spatrick               StringPrinter::StringElementType::UTF8>(options)) {
265*061da546Spatrick         stream.Printf("Summary Unavailable");
266*061da546Spatrick         return true;
267*061da546Spatrick       } else
268*061da546Spatrick         return true;
269*061da546Spatrick     } break;
270*061da546Spatrick     case eAddressTypeHost:
271*061da546Spatrick       break;
272*061da546Spatrick     case eAddressTypeInvalid:
273*061da546Spatrick     case eAddressTypeFile:
274*061da546Spatrick       break;
275*061da546Spatrick     }
276*061da546Spatrick   }
277*061da546Spatrick   return false;
278*061da546Spatrick }
279*061da546Spatrick 
280*061da546Spatrick bool lldb_private::formatters::LibStdcppWStringSummaryProvider(
281*061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
282*061da546Spatrick   const bool scalar_is_load_addr = true;
283*061da546Spatrick   AddressType addr_type;
284*061da546Spatrick   lldb::addr_t addr_of_string =
285*061da546Spatrick       valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
286*061da546Spatrick   if (addr_of_string != LLDB_INVALID_ADDRESS) {
287*061da546Spatrick     switch (addr_type) {
288*061da546Spatrick     case eAddressTypeLoad: {
289*061da546Spatrick       ProcessSP process_sp(valobj.GetProcessSP());
290*061da546Spatrick       if (!process_sp)
291*061da546Spatrick         return false;
292*061da546Spatrick 
293*061da546Spatrick       CompilerType wchar_compiler_type =
294*061da546Spatrick           valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
295*061da546Spatrick 
296*061da546Spatrick       if (!wchar_compiler_type)
297*061da546Spatrick         return false;
298*061da546Spatrick 
299*061da546Spatrick       // Safe to pass nullptr for exe_scope here.
300*061da546Spatrick       llvm::Optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
301*061da546Spatrick       if (!size)
302*061da546Spatrick         return false;
303*061da546Spatrick       const uint32_t wchar_size = *size;
304*061da546Spatrick 
305*061da546Spatrick       StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
306*061da546Spatrick       Status error;
307*061da546Spatrick       lldb::addr_t addr_of_data =
308*061da546Spatrick           process_sp->ReadPointerFromMemory(addr_of_string, error);
309*061da546Spatrick       if (error.Fail() || addr_of_data == 0 ||
310*061da546Spatrick           addr_of_data == LLDB_INVALID_ADDRESS)
311*061da546Spatrick         return false;
312*061da546Spatrick       options.SetLocation(addr_of_data);
313*061da546Spatrick       options.SetProcessSP(process_sp);
314*061da546Spatrick       options.SetStream(&stream);
315*061da546Spatrick       options.SetNeedsZeroTermination(false);
316*061da546Spatrick       options.SetBinaryZeroIsTerminator(false);
317*061da546Spatrick       lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
318*061da546Spatrick           addr_of_string + process_sp->GetAddressByteSize(), error);
319*061da546Spatrick       if (error.Fail())
320*061da546Spatrick         return false;
321*061da546Spatrick       options.SetSourceSize(size_of_data);
322*061da546Spatrick       options.SetPrefixToken("L");
323*061da546Spatrick 
324*061da546Spatrick       switch (wchar_size) {
325*061da546Spatrick       case 8:
326*061da546Spatrick         return StringPrinter::ReadStringAndDumpToStream<
327*061da546Spatrick             StringPrinter::StringElementType::UTF8>(options);
328*061da546Spatrick       case 16:
329*061da546Spatrick         return StringPrinter::ReadStringAndDumpToStream<
330*061da546Spatrick             StringPrinter::StringElementType::UTF16>(options);
331*061da546Spatrick       case 32:
332*061da546Spatrick         return StringPrinter::ReadStringAndDumpToStream<
333*061da546Spatrick             StringPrinter::StringElementType::UTF32>(options);
334*061da546Spatrick       default:
335*061da546Spatrick         stream.Printf("size for wchar_t is not valid");
336*061da546Spatrick         return true;
337*061da546Spatrick       }
338*061da546Spatrick       return true;
339*061da546Spatrick     } break;
340*061da546Spatrick     case eAddressTypeHost:
341*061da546Spatrick       break;
342*061da546Spatrick     case eAddressTypeInvalid:
343*061da546Spatrick     case eAddressTypeFile:
344*061da546Spatrick       break;
345*061da546Spatrick     }
346*061da546Spatrick   }
347*061da546Spatrick   return false;
348*061da546Spatrick }
349*061da546Spatrick 
350*061da546Spatrick LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
351*061da546Spatrick     lldb::ValueObjectSP valobj_sp)
352*061da546Spatrick     : SyntheticChildrenFrontEnd(*valobj_sp) {
353*061da546Spatrick   if (valobj_sp)
354*061da546Spatrick     Update();
355*061da546Spatrick }
356*061da546Spatrick 
357*061da546Spatrick size_t LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() { return 1; }
358*061da546Spatrick 
359*061da546Spatrick lldb::ValueObjectSP
360*061da546Spatrick LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
361*061da546Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
362*061da546Spatrick   if (!valobj_sp)
363*061da546Spatrick     return lldb::ValueObjectSP();
364*061da546Spatrick 
365*061da546Spatrick   if (idx == 0)
366*061da546Spatrick     return valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true);
367*061da546Spatrick   else
368*061da546Spatrick     return lldb::ValueObjectSP();
369*061da546Spatrick }
370*061da546Spatrick 
371*061da546Spatrick bool LibStdcppSharedPtrSyntheticFrontEnd::Update() { return false; }
372*061da546Spatrick 
373*061da546Spatrick bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; }
374*061da546Spatrick 
375*061da546Spatrick size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(
376*061da546Spatrick     ConstString name) {
377*061da546Spatrick   if (name == "_M_ptr")
378*061da546Spatrick     return 0;
379*061da546Spatrick   return UINT32_MAX;
380*061da546Spatrick }
381*061da546Spatrick 
382*061da546Spatrick SyntheticChildrenFrontEnd *
383*061da546Spatrick lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(
384*061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
385*061da546Spatrick   return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
386*061da546Spatrick                     : nullptr);
387*061da546Spatrick }
388*061da546Spatrick 
389*061da546Spatrick bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(
390*061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
391*061da546Spatrick   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
392*061da546Spatrick   if (!valobj_sp)
393*061da546Spatrick     return false;
394*061da546Spatrick 
395*061da546Spatrick   ValueObjectSP ptr_sp(
396*061da546Spatrick       valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true));
397*061da546Spatrick   if (!ptr_sp)
398*061da546Spatrick     return false;
399*061da546Spatrick 
400*061da546Spatrick   ValueObjectSP usecount_sp(valobj_sp->GetChildAtNamePath(
401*061da546Spatrick       {ConstString("_M_refcount"), ConstString("_M_pi"),
402*061da546Spatrick        ConstString("_M_use_count")}));
403*061da546Spatrick   if (!usecount_sp)
404*061da546Spatrick     return false;
405*061da546Spatrick 
406*061da546Spatrick   if (ptr_sp->GetValueAsUnsigned(0) == 0 ||
407*061da546Spatrick       usecount_sp->GetValueAsUnsigned(0) == 0) {
408*061da546Spatrick     stream.Printf("nullptr");
409*061da546Spatrick     return true;
410*061da546Spatrick   }
411*061da546Spatrick 
412*061da546Spatrick   Status error;
413*061da546Spatrick   ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
414*061da546Spatrick   if (pointee_sp && error.Success()) {
415*061da546Spatrick     if (pointee_sp->DumpPrintableRepresentation(
416*061da546Spatrick             stream, ValueObject::eValueObjectRepresentationStyleSummary,
417*061da546Spatrick             lldb::eFormatInvalid,
418*061da546Spatrick             ValueObject::PrintableRepresentationSpecialCases::eDisable,
419*061da546Spatrick             false)) {
420*061da546Spatrick       return true;
421*061da546Spatrick     }
422*061da546Spatrick   }
423*061da546Spatrick 
424*061da546Spatrick   stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
425*061da546Spatrick   return true;
426*061da546Spatrick }
427