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