1 //===-- LibCxx.cpp ----------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "LibCxx.h"
11 
12 #include "lldb/Core/DataBufferHeap.h"
13 #include "lldb/Core/Debugger.h"
14 #include "lldb/Core/Error.h"
15 #include "lldb/Core/FormatEntity.h"
16 #include "lldb/Core/Stream.h"
17 #include "lldb/Core/ValueObject.h"
18 #include "lldb/Core/ValueObjectConstResult.h"
19 #include "lldb/DataFormatters/FormattersHelpers.h"
20 #include "lldb/DataFormatters/StringPrinter.h"
21 #include "lldb/DataFormatters/TypeSummary.h"
22 #include "lldb/DataFormatters/VectorIterator.h"
23 #include "lldb/Host/Endian.h"
24 #include "lldb/Symbol/ClangASTContext.h"
25 #include "lldb/Target/Target.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 using namespace lldb_private::formatters;
30 
31 bool
32 lldb_private::formatters::LibcxxSmartPointerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
33 {
34     ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
35     if (!valobj_sp)
36         return false;
37     ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
38     ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath( {ConstString("__cntrl_"),ConstString("__shared_owners_")} ));
39     ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath( {ConstString("__cntrl_"),ConstString("__shared_weak_owners_")} ));
40 
41     if (!ptr_sp)
42         return false;
43 
44     if (ptr_sp->GetValueAsUnsigned(0) == 0)
45     {
46         stream.Printf("nullptr");
47         return true;
48     }
49     else
50     {
51         bool print_pointee = false;
52         Error error;
53         ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
54         if (pointee_sp && error.Success())
55         {
56             if (pointee_sp->DumpPrintableRepresentation(stream,
57                                                         ValueObject::eValueObjectRepresentationStyleSummary,
58                                                         lldb::eFormatInvalid,
59                                                         ValueObject::ePrintableRepresentationSpecialCasesDisable,
60                                                         false))
61                 print_pointee = true;
62         }
63         if (!print_pointee)
64             stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
65     }
66 
67     if (count_sp)
68         stream.Printf(" strong=%" PRIu64, 1+count_sp->GetValueAsUnsigned(0));
69 
70     if (weakcount_sp)
71         stream.Printf(" weak=%" PRIu64, 1+weakcount_sp->GetValueAsUnsigned(0));
72 
73     return true;
74 }
75 
76 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::LibcxxVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
77 SyntheticChildrenFrontEnd(*valobj_sp.get()),
78 m_bool_type(),
79 m_exe_ctx_ref(),
80 m_count(0),
81 m_base_data_address(0),
82 m_children()
83 {
84     if (valobj_sp)
85     {
86         Update();
87         m_bool_type = valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
88     }
89 }
90 
91 size_t
92 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
93 {
94     return m_count;
95 }
96 
97 lldb::ValueObjectSP
98 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
99 {
100     auto iter = m_children.find(idx),
101         end = m_children.end();
102     if (iter != end)
103         return iter->second;
104     if (idx >= m_count)
105         return ValueObjectSP();
106     if (m_base_data_address == 0 || m_count == 0)
107         return ValueObjectSP();
108     if (!m_bool_type)
109         return ValueObjectSP();
110     size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
111     size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
112     lldb::addr_t byte_location = m_base_data_address + byte_idx;
113     ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
114     if (!process_sp)
115         return ValueObjectSP();
116     uint8_t byte = 0;
117     uint8_t mask = 0;
118     Error err;
119     size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
120     if (err.Fail() || bytes_read == 0)
121         return ValueObjectSP();
122     switch (bit_index)
123     {
124         case 0:
125             mask = 1; break;
126         case 1:
127             mask = 2; break;
128         case 2:
129             mask = 4; break;
130         case 3:
131             mask = 8; break;
132         case 4:
133             mask = 16; break;
134         case 5:
135             mask = 32; break;
136         case 6:
137             mask = 64; break;
138         case 7:
139             mask = 128; break;
140         default:
141             return ValueObjectSP();
142     }
143     bool bit_set = ((byte & mask) != 0);
144     DataBufferSP buffer_sp(new DataBufferHeap(m_bool_type.GetByteSize(nullptr),0));
145     if (bit_set && buffer_sp && buffer_sp->GetBytes())
146         *(buffer_sp->GetBytes()) = 1; // regardless of endianness, anything non-zero is true
147     StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx);
148     ValueObjectSP retval_sp(CreateValueObjectFromData(name.GetData(), DataExtractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()), m_exe_ctx_ref, m_bool_type));
149     if (retval_sp)
150         m_children[idx] = retval_sp;
151     return retval_sp;
152 }
153 
154 /*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
155  __begin_ = 0x00000001001000e0
156  __size_ = 56
157  __cap_alloc_ = {
158  std::__1::__libcpp_compressed_pair_imp<unsigned long, std::__1::allocator<unsigned long> > = {
159  __first_ = 1
160  }
161  }
162  }*/
163 
164 bool
165 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update()
166 {
167     m_children.clear();
168     ValueObjectSP valobj_sp = m_backend.GetSP();
169     if (!valobj_sp)
170         return false;
171     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
172     ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName(ConstString("__size_"), true));
173     if (!size_sp)
174         return false;
175     m_count = size_sp->GetValueAsUnsigned(0);
176     if (!m_count)
177         return true;
178     ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true));
179     if (!begin_sp)
180     {
181         m_count = 0;
182         return false;
183     }
184     m_base_data_address = begin_sp->GetValueAsUnsigned(0);
185     if (!m_base_data_address)
186     {
187         m_count = 0;
188         return false;
189     }
190     return false;
191 }
192 
193 bool
194 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::MightHaveChildren ()
195 {
196     return true;
197 }
198 
199 size_t
200 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
201 {
202     if (!m_count || !m_base_data_address)
203         return UINT32_MAX;
204     const char* item_name = name.GetCString();
205     uint32_t idx = ExtractIndexFromString(item_name);
206     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
207         return UINT32_MAX;
208     return idx;
209 }
210 
211 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::~LibcxxVectorBoolSyntheticFrontEnd ()
212 {}
213 
214 SyntheticChildrenFrontEnd*
215 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
216 {
217     if (!valobj_sp)
218         return NULL;
219     return (new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp));
220 }
221 
222 /*
223  (lldb) fr var ibeg --raw --ptr-depth 1
224  (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, void *> *, long> >) ibeg = {
225  __i_ = {
226  __ptr_ = 0x0000000100103870 {
227  std::__1::__tree_node_base<void *> = {
228  std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = {
229  __left_ = 0x0000000000000000
230  }
231  __right_ = 0x0000000000000000
232  __parent_ = 0x00000001001038b0
233  __is_black_ = true
234  }
235  __value_ = {
236  first = 0
237  second = { std::string }
238  */
239 
240 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::LibCxxMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
241 SyntheticChildrenFrontEnd(*valobj_sp.get()),
242 m_pair_ptr()
243 {
244     if (valobj_sp)
245         Update();
246 }
247 
248 bool
249 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update()
250 {
251     ValueObjectSP valobj_sp = m_backend.GetSP();
252     if (!valobj_sp)
253         return false;
254 
255     TargetSP target_sp(valobj_sp->GetTargetSP());
256 
257     if (!target_sp)
258         return false;
259 
260     if (!valobj_sp)
261         return false;
262 
263     // this must be a ValueObject* because it is a child of the ValueObject we are producing children for
264     // it if were a ValueObjectSP, we would end up with a loop (iterator -> synthetic -> child -> parent == iterator)
265     // and that would in turn leak memory by never allowing the ValueObjects to die and free their memory
266     m_pair_ptr = valobj_sp->GetValueForExpressionPath(".__i_.__ptr_->__value_",
267                                                      NULL,
268                                                      NULL,
269                                                      NULL,
270                                                      ValueObject::GetValueForExpressionPathOptions().DontCheckDotVsArrowSyntax().SetSyntheticChildrenTraversal(ValueObject::GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None),
271                                                      NULL).get();
272 
273     return false;
274 }
275 
276 size_t
277 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::CalculateNumChildren ()
278 {
279     return 2;
280 }
281 
282 lldb::ValueObjectSP
283 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
284 {
285     if (!m_pair_ptr)
286         return lldb::ValueObjectSP();
287     return m_pair_ptr->GetChildAtIndex(idx, true);
288 }
289 
290 bool
291 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::MightHaveChildren ()
292 {
293     return true;
294 }
295 
296 size_t
297 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
298 {
299     if (name == ConstString("first"))
300         return 0;
301     if (name == ConstString("second"))
302         return 1;
303     return UINT32_MAX;
304 }
305 
306 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::~LibCxxMapIteratorSyntheticFrontEnd ()
307 {
308     // this will be deleted when its parent dies (since it's a child object)
309     //delete m_pair_ptr;
310 }
311 
312 SyntheticChildrenFrontEnd*
313 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
314 {
315     if (!valobj_sp)
316         return NULL;
317     return (new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp));
318 }
319 
320 /*
321  (lldb) fr var ibeg --raw --ptr-depth 1 -T
322  (std::__1::__wrap_iter<int *>) ibeg = {
323  (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
324  (int) *__i = 1
325  }
326  }
327 */
328 
329 SyntheticChildrenFrontEnd*
330 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
331 {
332     static ConstString g_item_name;
333     if (!g_item_name)
334         g_item_name.SetCString("__i");
335     if (!valobj_sp)
336         return NULL;
337     return (new VectorIteratorSyntheticFrontEnd(valobj_sp,g_item_name));
338 }
339 
340 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::LibcxxSharedPtrSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
341 SyntheticChildrenFrontEnd(*valobj_sp.get()),
342 m_cntrl(NULL),
343 m_count_sp(),
344 m_weak_count_sp(),
345 m_ptr_size(0),
346 m_byte_order(lldb::eByteOrderInvalid)
347 {
348     if (valobj_sp)
349         Update();
350 }
351 
352 size_t
353 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::CalculateNumChildren ()
354 {
355     return (m_cntrl ? 1 : 0);
356 }
357 
358 lldb::ValueObjectSP
359 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex (size_t idx)
360 {
361     if (!m_cntrl)
362         return lldb::ValueObjectSP();
363 
364     ValueObjectSP valobj_sp = m_backend.GetSP();
365     if (!valobj_sp)
366         return lldb::ValueObjectSP();
367 
368     if (idx == 0)
369         return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true);
370 
371     if (idx > 2)
372         return lldb::ValueObjectSP();
373 
374     if (idx == 1)
375     {
376         if (!m_count_sp)
377         {
378             ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName(ConstString("__shared_owners_"),true));
379             if (!shared_owners_sp)
380                 return lldb::ValueObjectSP();
381             uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0);
382             DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
383             m_count_sp = CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_owners_sp->GetCompilerType());
384         }
385         return m_count_sp;
386     }
387     else /* if (idx == 2) */
388     {
389         if (!m_weak_count_sp)
390         {
391             ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName(ConstString("__shared_weak_owners_"),true));
392             if (!shared_weak_owners_sp)
393                 return lldb::ValueObjectSP();
394             uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0);
395             DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
396             m_weak_count_sp = CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_weak_owners_sp->GetCompilerType());
397         }
398         return m_weak_count_sp;
399     }
400 }
401 
402 bool
403 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update()
404 {
405     m_count_sp.reset();
406     m_weak_count_sp.reset();
407     m_cntrl = NULL;
408 
409     ValueObjectSP valobj_sp = m_backend.GetSP();
410     if (!valobj_sp)
411         return false;
412 
413     TargetSP target_sp(valobj_sp->GetTargetSP());
414     if (!target_sp)
415         return false;
416 
417     m_byte_order = target_sp->GetArchitecture().GetByteOrder();
418     m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize();
419 
420     lldb::ValueObjectSP cntrl_sp(valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"),true));
421 
422     m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular dependency
423     return false;
424 }
425 
426 bool
427 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::MightHaveChildren ()
428 {
429     return true;
430 }
431 
432 size_t
433 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
434 {
435     if (name == ConstString("__ptr_"))
436         return 0;
437     if (name == ConstString("count"))
438         return 1;
439     if (name == ConstString("weak_count"))
440         return 2;
441     return UINT32_MAX;
442 }
443 
444 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::~LibcxxSharedPtrSyntheticFrontEnd ()
445 {}
446 
447 SyntheticChildrenFrontEnd*
448 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
449 {
450     if (!valobj_sp)
451         return NULL;
452     return (new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp));
453 }
454 
455 bool
456 lldb_private::formatters::LibcxxContainerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
457 {
458     if (valobj.IsPointerType())
459     {
460         uint64_t value = valobj.GetValueAsUnsigned(0);
461         if (!value)
462             return false;
463         stream.Printf("0x%016" PRIx64 " ", value);
464     }
465     return FormatEntity::FormatStringRef("size=${svar%#}", stream, NULL, NULL, NULL, &valobj, false, false);
466 }
467 
468 // the field layout in a libc++ string (cap, side, data or data, size, cap)
469 enum LibcxxStringLayoutMode
470 {
471     eLibcxxStringLayoutModeCSD = 0,
472     eLibcxxStringLayoutModeDSC = 1,
473     eLibcxxStringLayoutModeInvalid = 0xffff
474 };
475 
476 // this function abstracts away the layout and mode details of a libc++ string
477 // and returns the address of the data and the size ready for callers to consume
478 static bool
479 ExtractLibcxxStringInfo (ValueObject& valobj,
480                          ValueObjectSP &location_sp,
481                          uint64_t& size)
482 {
483     ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
484     if (!D)
485         return false;
486 
487     ValueObjectSP layout_decider(D->GetChildAtIndexPath({0,0}));
488 
489     // this child should exist
490     if (!layout_decider)
491         return false;
492 
493     ConstString g_data_name("__data_");
494     ConstString g_size_name("__size_");
495     bool short_mode = false; // this means the string is in short-mode and the data is stored inline
496     LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) ? eLibcxxStringLayoutModeDSC : eLibcxxStringLayoutModeCSD;
497     uint64_t size_mode_value = 0;
498 
499     if (layout == eLibcxxStringLayoutModeDSC)
500     {
501         ValueObjectSP size_mode(D->GetChildAtIndexPath({1,1,0}));
502         if (!size_mode)
503             return false;
504 
505         if (size_mode->GetName() != g_size_name)
506         {
507             // we are hitting the padding structure, move along
508             size_mode = D->GetChildAtIndexPath({1,1,1});
509             if (!size_mode)
510                 return false;
511         }
512 
513         size_mode_value = (size_mode->GetValueAsUnsigned(0));
514         short_mode = ((size_mode_value & 0x80) == 0);
515     }
516     else
517     {
518         ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
519         if (!size_mode)
520             return false;
521 
522         size_mode_value = (size_mode->GetValueAsUnsigned(0));
523         short_mode = ((size_mode_value & 1) == 0);
524     }
525 
526     if (short_mode)
527     {
528         ValueObjectSP s(D->GetChildAtIndex(1, true));
529         if (!s)
530             return false;
531         location_sp = s->GetChildAtIndex((layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true);
532         size = (layout == eLibcxxStringLayoutModeDSC) ? size_mode_value : ((size_mode_value >> 1) % 256);
533         return (location_sp.get() != nullptr);
534     }
535     else
536     {
537         ValueObjectSP l(D->GetChildAtIndex(0, true));
538         if (!l)
539             return false;
540         // we can use the layout_decider object as the data pointer
541         location_sp = (layout == eLibcxxStringLayoutModeDSC) ? layout_decider : l->GetChildAtIndex(2, true);
542         ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
543         if (!size_vo || !location_sp)
544             return false;
545         size = size_vo->GetValueAsUnsigned(0);
546         return true;
547     }
548 }
549 
550 bool
551 lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& summary_options)
552 {
553     uint64_t size = 0;
554     ValueObjectSP location_sp((ValueObject*)nullptr);
555     if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
556         return false;
557     if (size == 0)
558     {
559         stream.Printf("L\"\"");
560         return true;
561     }
562     if (!location_sp)
563         return false;
564 
565     DataExtractor extractor;
566     if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped)
567         size = std::min<decltype(size)>(size, valobj.GetTargetSP()->GetMaximumSizeOfStringSummary());
568     location_sp->GetPointeeData(extractor, 0, size);
569 
570     // std::wstring::size() is measured in 'characters', not bytes
571     auto wchar_t_size = valobj.GetTargetSP()->GetScratchClangASTContext()->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);
572 
573     StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
574     options.SetData(extractor);
575     options.SetStream(&stream);
576     options.SetPrefixToken('L');
577     options.SetQuote('"');
578     options.SetSourceSize(size);
579     options.SetBinaryZeroIsTerminator(false);
580 
581     switch (wchar_t_size)
582     {
583         case 1:
584             StringPrinter::ReadBufferAndDumpToStream<lldb_private::formatters::StringPrinter::StringElementType::UTF8>(options);
585             break;
586 
587         case 2:
588             lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<lldb_private::formatters::StringPrinter::StringElementType::UTF16>(options);
589             break;
590 
591         case 4:
592             lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<lldb_private::formatters::StringPrinter::StringElementType::UTF32>(options);
593             break;
594 
595         default:
596             stream.Printf("size for wchar_t is not valid");
597             return true;
598     }
599 
600     return true;
601 }
602 
603 bool
604 lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& summary_options)
605 {
606     uint64_t size = 0;
607     ValueObjectSP location_sp((ValueObject*)nullptr);
608 
609     if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
610         return false;
611 
612     if (size == 0)
613     {
614         stream.Printf("\"\"");
615         return true;
616     }
617 
618     if (!location_sp)
619         return false;
620 
621     DataExtractor extractor;
622     if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped)
623         size = std::min<decltype(size)>(size, valobj.GetTargetSP()->GetMaximumSizeOfStringSummary());
624     location_sp->GetPointeeData(extractor, 0, size);
625 
626     StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
627     options.SetData(extractor);
628     options.SetStream(&stream);
629     options.SetPrefixToken(0);
630     options.SetQuote('"');
631     options.SetSourceSize(size);
632     options.SetBinaryZeroIsTerminator(false);
633     StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::ASCII>(options);
634 
635     return true;
636 }
637