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