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/Debugger.h"
17 #include "lldb/Core/FormatEntity.h"
18 #include "lldb/Core/ValueObject.h"
19 #include "lldb/Core/ValueObjectConstResult.h"
20 #include "lldb/DataFormatters/FormattersHelpers.h"
21 #include "lldb/DataFormatters/StringPrinter.h"
22 #include "lldb/DataFormatters/TypeSummary.h"
23 #include "lldb/DataFormatters/VectorIterator.h"
24 #include "lldb/Symbol/ClangASTContext.h"
25 #include "lldb/Target/ProcessStructReader.h"
26 #include "lldb/Target/Target.h"
27 #include "lldb/Utility/DataBufferHeap.h"
28 #include "lldb/Utility/Endian.h"
29 #include "lldb/Utility/Error.h"
30 #include "lldb/Utility/Stream.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.GetString(), 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,
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
294                      ->GetValueForExpressionPath(
295                          ".__i_.__ptr_", nullptr, nullptr,
296                          ValueObject::GetValueForExpressionPathOptions()
297                              .DontCheckDotVsArrowSyntax()
298                              .SetSyntheticChildrenTraversal(
299                                  ValueObject::GetValueForExpressionPathOptions::
300                                      SyntheticChildrenTraversal::None),
301                          nullptr)
302                      .get();
303     if (m_pair_ptr) {
304       auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true));
305       lldb::TemplateArgumentKind kind;
306       if (!__i_) {
307         m_pair_ptr = nullptr;
308         return false;
309       }
310       CompilerType pair_type(__i_->GetCompilerType().GetTemplateArgument(0, kind));
311       std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr;
312       pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
313       if (!pair_type) {
314         m_pair_ptr = nullptr;
315         return false;
316       }
317 
318       auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS));
319       m_pair_ptr = nullptr;
320       if (addr && addr!=LLDB_INVALID_ADDRESS) {
321         ClangASTContext *ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem());
322         if (!ast_ctx)
323           return false;
324         CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), {
325           {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
326           {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
327           {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
328           {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
329           {"payload",pair_type}
330         });
331         DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0));
332         ProcessSP process_sp(target_sp->GetProcessSP());
333         Error error;
334         process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error);
335         if (error.Fail())
336           return false;
337         DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
338         auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type);
339         if (pair_sp)
340           m_pair_sp = pair_sp->GetChildAtIndex(4,true);
341       }
342     }
343   }
344 
345   return false;
346 }
347 
348 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
349     CalculateNumChildren() {
350   return 2;
351 }
352 
353 lldb::ValueObjectSP
354 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex(
355     size_t idx) {
356   if (m_pair_ptr)
357     return m_pair_ptr->GetChildAtIndex(idx, true);
358   if (m_pair_sp)
359     return m_pair_sp->GetChildAtIndex(idx, true);
360   return lldb::ValueObjectSP();
361 }
362 
363 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
364     MightHaveChildren() {
365   return true;
366 }
367 
368 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
369     GetIndexOfChildWithName(const ConstString &name) {
370   if (name == ConstString("first"))
371     return 0;
372   if (name == ConstString("second"))
373     return 1;
374   return UINT32_MAX;
375 }
376 
377 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
378     ~LibCxxMapIteratorSyntheticFrontEnd() {
379   // this will be deleted when its parent dies (since it's a child object)
380   // delete m_pair_ptr;
381 }
382 
383 SyntheticChildrenFrontEnd *
384 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator(
385     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
386   return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp)
387                     : nullptr);
388 }
389 
390 /*
391  (lldb) fr var ibeg --raw --ptr-depth 1 -T
392  (std::__1::__wrap_iter<int *>) ibeg = {
393  (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
394  (int) *__i = 1
395  }
396  }
397 */
398 
399 SyntheticChildrenFrontEnd *
400 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(
401     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
402   static ConstString g_item_name;
403   if (!g_item_name)
404     g_item_name.SetCString("__i");
405   return (valobj_sp
406               ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name)
407               : nullptr);
408 }
409 
410 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
411     LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
412     : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(),
413       m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) {
414   if (valobj_sp)
415     Update();
416 }
417 
418 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
419     CalculateNumChildren() {
420   return (m_cntrl ? 1 : 0);
421 }
422 
423 lldb::ValueObjectSP
424 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(
425     size_t idx) {
426   if (!m_cntrl)
427     return lldb::ValueObjectSP();
428 
429   ValueObjectSP valobj_sp = m_backend.GetSP();
430   if (!valobj_sp)
431     return lldb::ValueObjectSP();
432 
433   if (idx == 0)
434     return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true);
435 
436   if (idx > 2)
437     return lldb::ValueObjectSP();
438 
439   if (idx == 1) {
440     if (!m_count_sp) {
441       ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName(
442           ConstString("__shared_owners_"), true));
443       if (!shared_owners_sp)
444         return lldb::ValueObjectSP();
445       uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0);
446       DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
447       m_count_sp = CreateValueObjectFromData(
448           "count", data, valobj_sp->GetExecutionContextRef(),
449           shared_owners_sp->GetCompilerType());
450     }
451     return m_count_sp;
452   } else /* if (idx == 2) */
453   {
454     if (!m_weak_count_sp) {
455       ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName(
456           ConstString("__shared_weak_owners_"), true));
457       if (!shared_weak_owners_sp)
458         return lldb::ValueObjectSP();
459       uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0);
460       DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
461       m_weak_count_sp = CreateValueObjectFromData(
462           "count", data, valobj_sp->GetExecutionContextRef(),
463           shared_weak_owners_sp->GetCompilerType());
464     }
465     return m_weak_count_sp;
466   }
467 }
468 
469 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {
470   m_count_sp.reset();
471   m_weak_count_sp.reset();
472   m_cntrl = nullptr;
473 
474   ValueObjectSP valobj_sp = m_backend.GetSP();
475   if (!valobj_sp)
476     return false;
477 
478   TargetSP target_sp(valobj_sp->GetTargetSP());
479   if (!target_sp)
480     return false;
481 
482   m_byte_order = target_sp->GetArchitecture().GetByteOrder();
483   m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize();
484 
485   lldb::ValueObjectSP cntrl_sp(
486       valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true));
487 
488   m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular
489                             // dependency
490   return false;
491 }
492 
493 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
494     MightHaveChildren() {
495   return true;
496 }
497 
498 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
499     GetIndexOfChildWithName(const ConstString &name) {
500   if (name == ConstString("__ptr_"))
501     return 0;
502   if (name == ConstString("count"))
503     return 1;
504   if (name == ConstString("weak_count"))
505     return 2;
506   return UINT32_MAX;
507 }
508 
509 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
510     ~LibcxxSharedPtrSyntheticFrontEnd() = default;
511 
512 SyntheticChildrenFrontEnd *
513 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(
514     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
515   return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)
516                     : nullptr);
517 }
518 
519 bool lldb_private::formatters::LibcxxContainerSummaryProvider(
520     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
521   if (valobj.IsPointerType()) {
522     uint64_t value = valobj.GetValueAsUnsigned(0);
523     if (!value)
524       return false;
525     stream.Printf("0x%016" PRIx64 " ", value);
526   }
527   return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr,
528                                        nullptr, nullptr, &valobj, false, false);
529 }
530 
531 // the field layout in a libc++ string (cap, side, data or data, size, cap)
532 enum LibcxxStringLayoutMode {
533   eLibcxxStringLayoutModeCSD = 0,
534   eLibcxxStringLayoutModeDSC = 1,
535   eLibcxxStringLayoutModeInvalid = 0xffff
536 };
537 
538 // this function abstracts away the layout and mode details of a libc++ string
539 // and returns the address of the data and the size ready for callers to consume
540 static bool ExtractLibcxxStringInfo(ValueObject &valobj,
541                                     ValueObjectSP &location_sp,
542                                     uint64_t &size) {
543   ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0}));
544   if (!D)
545     return false;
546 
547   ValueObjectSP layout_decider(D->GetChildAtIndexPath({0, 0}));
548 
549   // this child should exist
550   if (!layout_decider)
551     return false;
552 
553   ConstString g_data_name("__data_");
554   ConstString g_size_name("__size_");
555   bool short_mode = false; // this means the string is in short-mode and the
556                            // data is stored inline
557   LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name)
558                                       ? eLibcxxStringLayoutModeDSC
559                                       : eLibcxxStringLayoutModeCSD;
560   uint64_t size_mode_value = 0;
561 
562   if (layout == eLibcxxStringLayoutModeDSC) {
563     ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0}));
564     if (!size_mode)
565       return false;
566 
567     if (size_mode->GetName() != g_size_name) {
568       // we are hitting the padding structure, move along
569       size_mode = D->GetChildAtIndexPath({1, 1, 1});
570       if (!size_mode)
571         return false;
572     }
573 
574     size_mode_value = (size_mode->GetValueAsUnsigned(0));
575     short_mode = ((size_mode_value & 0x80) == 0);
576   } else {
577     ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0}));
578     if (!size_mode)
579       return false;
580 
581     size_mode_value = (size_mode->GetValueAsUnsigned(0));
582     short_mode = ((size_mode_value & 1) == 0);
583   }
584 
585   if (short_mode) {
586     ValueObjectSP s(D->GetChildAtIndex(1, true));
587     if (!s)
588       return false;
589     location_sp = s->GetChildAtIndex(
590         (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true);
591     size = (layout == eLibcxxStringLayoutModeDSC)
592                ? size_mode_value
593                : ((size_mode_value >> 1) % 256);
594     return (location_sp.get() != nullptr);
595   } else {
596     ValueObjectSP l(D->GetChildAtIndex(0, true));
597     if (!l)
598       return false;
599     // we can use the layout_decider object as the data pointer
600     location_sp = (layout == eLibcxxStringLayoutModeDSC)
601                       ? layout_decider
602                       : l->GetChildAtIndex(2, true);
603     ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
604     if (!size_vo || !location_sp)
605       return false;
606     size = size_vo->GetValueAsUnsigned(0);
607     return true;
608   }
609 }
610 
611 bool lldb_private::formatters::LibcxxWStringSummaryProvider(
612     ValueObject &valobj, Stream &stream,
613     const TypeSummaryOptions &summary_options) {
614   uint64_t size = 0;
615   ValueObjectSP location_sp;
616   if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
617     return false;
618   if (size == 0) {
619     stream.Printf("L\"\"");
620     return true;
621   }
622   if (!location_sp)
623     return false;
624 
625   DataExtractor extractor;
626 
627   StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
628 
629   if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
630     const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
631     if (size > max_size) {
632       size = max_size;
633       options.SetIsTruncated(true);
634     }
635   }
636   location_sp->GetPointeeData(extractor, 0, size);
637 
638   // std::wstring::size() is measured in 'characters', not bytes
639   auto wchar_t_size = valobj.GetTargetSP()
640                           ->GetScratchClangASTContext()
641                           ->GetBasicType(lldb::eBasicTypeWChar)
642                           .GetByteSize(nullptr);
643 
644   options.SetData(extractor);
645   options.SetStream(&stream);
646   options.SetPrefixToken("L");
647   options.SetQuote('"');
648   options.SetSourceSize(size);
649   options.SetBinaryZeroIsTerminator(false);
650 
651   switch (wchar_t_size) {
652   case 1:
653     StringPrinter::ReadBufferAndDumpToStream<
654         lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
655         options);
656     break;
657 
658   case 2:
659     lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<
660         lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
661         options);
662     break;
663 
664   case 4:
665     lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<
666         lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
667         options);
668     break;
669 
670   default:
671     stream.Printf("size for wchar_t is not valid");
672     return true;
673   }
674 
675   return true;
676 }
677 
678 bool lldb_private::formatters::LibcxxStringSummaryProvider(
679     ValueObject &valobj, Stream &stream,
680     const TypeSummaryOptions &summary_options) {
681   uint64_t size = 0;
682   ValueObjectSP location_sp;
683 
684   if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
685     return false;
686 
687   if (size == 0) {
688     stream.Printf("\"\"");
689     return true;
690   }
691 
692   if (!location_sp)
693     return false;
694 
695   StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
696 
697   DataExtractor extractor;
698   if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
699     const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
700     if (size > max_size) {
701       size = max_size;
702       options.SetIsTruncated(true);
703     }
704   }
705   location_sp->GetPointeeData(extractor, 0, size);
706 
707   options.SetData(extractor);
708   options.SetStream(&stream);
709   options.SetPrefixToken(nullptr);
710   options.SetQuote('"');
711   options.SetSourceSize(size);
712   options.SetBinaryZeroIsTerminator(false);
713   StringPrinter::ReadBufferAndDumpToStream<
714       StringPrinter::StringElementType::ASCII>(options);
715 
716   return true;
717 }
718 
719 class LibcxxFunctionFrontEnd : public SyntheticValueProviderFrontEnd {
720 public:
721   LibcxxFunctionFrontEnd(ValueObject &backend)
722       : SyntheticValueProviderFrontEnd(backend) {}
723 
724   lldb::ValueObjectSP GetSyntheticValue() override {
725     static ConstString g___f_("__f_");
726     return m_backend.GetChildMemberWithName(g___f_, true);
727   }
728 };
729 
730 SyntheticChildrenFrontEnd *
731 lldb_private::formatters::LibcxxFunctionFrontEndCreator(
732     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
733   if (valobj_sp)
734     return new LibcxxFunctionFrontEnd(*valobj_sp);
735   return nullptr;
736 }
737