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