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/ProcessStructReader.h"
27 #include "lldb/Target/SectionLoadList.h"
28 #include "lldb/Target/Target.h"
29 #include "lldb/Utility/DataBufferHeap.h"
30 #include "lldb/Utility/Endian.h"
31 #include "lldb/Utility/Status.h"
32 #include "lldb/Utility/Stream.h"
33 
34 using namespace lldb;
35 using namespace lldb_private;
36 using namespace lldb_private::formatters;
37 
38 bool lldb_private::formatters::LibcxxOptionalSummaryProvider(
39     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
40   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
41   if (!valobj_sp)
42     return false;
43 
44   // An optional either contains a value or not, the member __engaged_ is
45   // a bool flag, it is true if the optional has a value and false otherwise.
46   ValueObjectSP engaged_sp(
47       valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true));
48 
49   if (!engaged_sp)
50     return false;
51 
52   llvm::StringRef engaged_as_cstring(
53       engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false");
54 
55   stream.Printf(" Has Value=%s ", engaged_as_cstring.data());
56 
57   return true;
58 }
59 
60 bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
61     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
62 
63   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
64 
65   if (!valobj_sp)
66     return false;
67 
68   // Member __f_ has type __base*, the contents of which will hold:
69   // 1) a vtable entry which may hold type information needed to discover the
70   //    lambda being called
71   // 2) possibly hold a pointer to the callable object
72   // e.g.
73   //
74   // (lldb) frame var -R  f_display
75   // (std::__1::function<void (int)>) f_display = {
76   //  __buf_ = {
77   //  …
78   // }
79   //  __f_ = 0x00007ffeefbffa00
80   // }
81   // (lldb) memory read -fA 0x00007ffeefbffa00
82   // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ...
83   // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ...
84   //
85   // We will be handling five cases below, std::function is wrapping:
86   //
87   // 1) a lambda we know at compile time. We will obtain the name of the lambda
88   //    from the first template pameter from __func's vtable. We will look up
89   //    the lambda's operator()() and obtain the line table entry.
90   // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method
91   //    will be stored after the vtable. We will obtain the lambdas name from
92   //    this entry and lookup operator()() and obtain the line table entry.
93   // 3) a callable object via operator()(). We will obtain the name of the
94   //    object from the first template parameter from __func's vtable. We will
95   //    look up the objectc operator()() and obtain the line table entry.
96   // 4) a member function. A pointer to the function will stored after the
97   //    we will obtain the name from this pointer.
98   // 5) a free function. A pointer to the function will stored after the vtable
99   //    we will obtain the name from this pointer.
100   ValueObjectSP member__f_(
101       valobj_sp->GetChildMemberWithName(ConstString("__f_"), true));
102   lldb::addr_t member__f_pointer_value = member__f_->GetValueAsUnsigned(0);
103 
104   ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
105   Process *process = exe_ctx.GetProcessPtr();
106 
107   if (process == nullptr)
108     return false;
109 
110   uint32_t address_size = process->GetAddressByteSize();
111   Status status;
112 
113   // First item pointed to by __f_ should be the pointer to the vtable for
114   // a __base object.
115   lldb::addr_t vtable_address =
116       process->ReadPointerFromMemory(member__f_pointer_value, status);
117 
118   if (status.Fail())
119     return false;
120 
121   bool found_wrapped_function = false;
122 
123   // Using scoped exit so we can use early return and still execute the default
124   // action in case we don't find the wrapper function. Otherwise we can't use
125   // early exit without duplicating code.
126   auto default_print_on_exit = llvm::make_scope_exit(
127       [&found_wrapped_function, &stream, &member__f_pointer_value]() {
128         if (!found_wrapped_function)
129           stream.Printf(" __f_ = %" PRIu64, member__f_pointer_value);
130       });
131 
132   lldb::addr_t address_after_vtable = member__f_pointer_value + address_size;
133   // As commened above we may not have a function pointer but if we do we will
134   // need it.
135   lldb::addr_t possible_function_address =
136       process->ReadPointerFromMemory(address_after_vtable, status);
137 
138   if (status.Fail())
139     return false;
140 
141   Target &target = process->GetTarget();
142 
143   if (target.GetSectionLoadList().IsEmpty())
144     return false;
145 
146   Address vtable_addr_resolved;
147   SymbolContext sc;
148   Symbol *symbol;
149 
150   if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address,
151                                                       vtable_addr_resolved))
152     return false;
153 
154   target.GetImages().ResolveSymbolContextForAddress(
155       vtable_addr_resolved, eSymbolContextEverything, sc);
156   symbol = sc.symbol;
157 
158   if (symbol == NULL)
159     return false;
160 
161   llvm::StringRef vtable_name(symbol->GetName().GetCString());
162   bool found_expected_start_string =
163       vtable_name.startswith("vtable for std::__1::__function::__func<");
164 
165   if (!found_expected_start_string)
166     return false;
167 
168   // Given case 1 or 3 we have a vtable name, we are want to extract the first
169   // template parameter
170   //
171   //  ... __func<main::$_0, std::__1::allocator<main::$_0> ...
172   //             ^^^^^^^^^
173   //
174   // We do this by find the first < and , and extracting in between.
175   //
176   // This covers the case of the lambda known at compile time.
177   //
178   size_t first_open_angle_bracket = vtable_name.find('<') + 1;
179   size_t first_comma = vtable_name.find_first_of(',');
180 
181   llvm::StringRef first_template_parameter =
182       vtable_name.slice(first_open_angle_bracket, first_comma);
183 
184   Address function_address_resolved;
185 
186   // Setup for cases 2, 4 and 5 we have a pointer to a function after the
187   // vtable. We will use a process of elimination to drop through each case
188   // and obtain the data we need.
189   if (target.GetSectionLoadList().ResolveLoadAddress(
190           possible_function_address, function_address_resolved)) {
191     target.GetImages().ResolveSymbolContextForAddress(
192         function_address_resolved, eSymbolContextEverything, sc);
193     symbol = sc.symbol;
194   }
195 
196   auto get_name = [&first_template_parameter, &symbol]() {
197     // Given case 1:
198     //
199     //    main::$_0
200     //
201     // we want to append ::operator()()
202     if (first_template_parameter.contains("$_"))
203       return llvm::Regex::escape(first_template_parameter.str()) +
204              R"(::operator\(\)\(.*\))";
205 
206     if (symbol != NULL &&
207         symbol->GetName().GetStringRef().contains("__invoke")) {
208 
209       llvm::StringRef symbol_name = symbol->GetName().GetStringRef();
210       size_t pos2 = symbol_name.find_last_of(':');
211 
212       // Given case 2:
213       //
214       //    main::$_1::__invoke(...)
215       //
216       // We want to slice off __invoke(...) and append operator()()
217       std::string lambda_operator =
218           llvm::Regex::escape(symbol_name.slice(0, pos2 + 1).str()) +
219           R"(operator\(\)\(.*\))";
220 
221       return lambda_operator;
222     }
223 
224     // Case 3
225     return first_template_parameter.str() + R"(::operator\(\)\(.*\))";
226     ;
227   };
228 
229   std::string func_to_match = get_name();
230 
231   SymbolContextList scl;
232 
233   target.GetImages().FindFunctions(RegularExpression{func_to_match}, true, true,
234                                    true, scl);
235 
236   // Case 1,2 or 3
237   if (scl.GetSize() >= 1) {
238     SymbolContext sc2 = scl[0];
239 
240     AddressRange range;
241     sc2.GetAddressRange(eSymbolContextEverything, 0, false, range);
242 
243     Address address = range.GetBaseAddress();
244 
245     Address addr;
246     if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target),
247                                   addr)) {
248       LineEntry line_entry;
249       addr.CalculateSymbolContextLineEntry(line_entry);
250 
251       found_wrapped_function = true;
252       if (first_template_parameter.contains("$_") ||
253           (symbol != NULL &&
254            symbol->GetName().GetStringRef().contains("__invoke"))) {
255         // Case 1 and 2
256         stream.Printf(" Lambda in File %s at Line %u",
257                       line_entry.file.GetFilename().GetCString(),
258                       line_entry.line);
259       } else {
260         // Case 3
261         stream.Printf(" Function in File %s at Line %u",
262                       line_entry.file.GetFilename().GetCString(),
263                       line_entry.line);
264       }
265 
266       return true;
267     }
268   }
269 
270   // Case 4 or 5
271   if (!symbol->GetName().GetStringRef().startswith("vtable for")) {
272     found_wrapped_function = true;
273     stream.Printf(" Function = %s ", symbol->GetName().GetCString());
274     return true;
275   }
276 
277   return false;
278 }
279 
280 bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
281     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
282   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
283   if (!valobj_sp)
284     return false;
285   ValueObjectSP ptr_sp(
286       valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
287   ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath(
288       {ConstString("__cntrl_"), ConstString("__shared_owners_")}));
289   ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath(
290       {ConstString("__cntrl_"), ConstString("__shared_weak_owners_")}));
291 
292   if (!ptr_sp)
293     return false;
294 
295   if (ptr_sp->GetValueAsUnsigned(0) == 0) {
296     stream.Printf("nullptr");
297     return true;
298   } else {
299     bool print_pointee = false;
300     Status error;
301     ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
302     if (pointee_sp && error.Success()) {
303       if (pointee_sp->DumpPrintableRepresentation(
304               stream, ValueObject::eValueObjectRepresentationStyleSummary,
305               lldb::eFormatInvalid,
306               ValueObject::PrintableRepresentationSpecialCases::eDisable,
307               false))
308         print_pointee = true;
309     }
310     if (!print_pointee)
311       stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
312   }
313 
314   if (count_sp)
315     stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0));
316 
317   if (weakcount_sp)
318     stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0));
319 
320   return true;
321 }
322 
323 /*
324  (lldb) fr var ibeg --raw --ptr-depth 1
325  (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int,
326  std::__1::basic_string<char, std::__1::char_traits<char>,
327  std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int,
328  std::__1::basic_string<char, std::__1::char_traits<char>,
329  std::__1::allocator<char> > >, void *> *, long> >) ibeg = {
330  __i_ = {
331  __ptr_ = 0x0000000100103870 {
332  std::__1::__tree_node_base<void *> = {
333  std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = {
334  __left_ = 0x0000000000000000
335  }
336  __right_ = 0x0000000000000000
337  __parent_ = 0x00000001001038b0
338  __is_black_ = true
339  }
340  __value_ = {
341  first = 0
342  second = { std::string }
343  */
344 
345 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
346     LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
347     : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() {
348   if (valobj_sp)
349     Update();
350 }
351 
352 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
353   m_pair_sp.reset();
354   m_pair_ptr = nullptr;
355 
356   ValueObjectSP valobj_sp = m_backend.GetSP();
357   if (!valobj_sp)
358     return false;
359 
360   TargetSP target_sp(valobj_sp->GetTargetSP());
361 
362   if (!target_sp)
363     return false;
364 
365   if (!valobj_sp)
366     return false;
367 
368   static ConstString g___i_("__i_");
369 
370   // this must be a ValueObject* because it is a child of the ValueObject we
371   // are producing children for it if were a ValueObjectSP, we would end up
372   // with a loop (iterator -> synthetic -> child -> parent == iterator) and
373   // that would in turn leak memory by never allowing the ValueObjects to die
374   // and free their memory
375   m_pair_ptr = valobj_sp
376                    ->GetValueForExpressionPath(
377                        ".__i_.__ptr_->__value_", nullptr, nullptr,
378                        ValueObject::GetValueForExpressionPathOptions()
379                            .DontCheckDotVsArrowSyntax()
380                            .SetSyntheticChildrenTraversal(
381                                ValueObject::GetValueForExpressionPathOptions::
382                                    SyntheticChildrenTraversal::None),
383                        nullptr)
384                    .get();
385 
386   if (!m_pair_ptr) {
387     m_pair_ptr = valobj_sp
388                      ->GetValueForExpressionPath(
389                          ".__i_.__ptr_", nullptr, nullptr,
390                          ValueObject::GetValueForExpressionPathOptions()
391                              .DontCheckDotVsArrowSyntax()
392                              .SetSyntheticChildrenTraversal(
393                                  ValueObject::GetValueForExpressionPathOptions::
394                                      SyntheticChildrenTraversal::None),
395                          nullptr)
396                      .get();
397     if (m_pair_ptr) {
398       auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true));
399       if (!__i_) {
400         m_pair_ptr = nullptr;
401         return false;
402       }
403       CompilerType pair_type(__i_->GetCompilerType().GetTypeTemplateArgument(0));
404       std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr;
405       pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
406       if (!pair_type) {
407         m_pair_ptr = nullptr;
408         return false;
409       }
410 
411       auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS));
412       m_pair_ptr = nullptr;
413       if (addr && addr!=LLDB_INVALID_ADDRESS) {
414         ClangASTContext *ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem());
415         if (!ast_ctx)
416           return false;
417         CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), {
418           {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
419           {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
420           {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
421           {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
422           {"payload",pair_type}
423         });
424         DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0));
425         ProcessSP process_sp(target_sp->GetProcessSP());
426         Status error;
427         process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error);
428         if (error.Fail())
429           return false;
430         DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
431         auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type);
432         if (pair_sp)
433           m_pair_sp = pair_sp->GetChildAtIndex(4,true);
434       }
435     }
436   }
437 
438   return false;
439 }
440 
441 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
442     CalculateNumChildren() {
443   return 2;
444 }
445 
446 lldb::ValueObjectSP
447 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex(
448     size_t idx) {
449   if (m_pair_ptr)
450     return m_pair_ptr->GetChildAtIndex(idx, true);
451   if (m_pair_sp)
452     return m_pair_sp->GetChildAtIndex(idx, true);
453   return lldb::ValueObjectSP();
454 }
455 
456 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
457     MightHaveChildren() {
458   return true;
459 }
460 
461 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
462     GetIndexOfChildWithName(const ConstString &name) {
463   if (name == ConstString("first"))
464     return 0;
465   if (name == ConstString("second"))
466     return 1;
467   return UINT32_MAX;
468 }
469 
470 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
471     ~LibCxxMapIteratorSyntheticFrontEnd() {
472   // this will be deleted when its parent dies (since it's a child object)
473   // delete m_pair_ptr;
474 }
475 
476 SyntheticChildrenFrontEnd *
477 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator(
478     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
479   return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp)
480                     : nullptr);
481 }
482 
483 /*
484  (lldb) fr var ibeg --raw --ptr-depth 1 -T
485  (std::__1::__wrap_iter<int *>) ibeg = {
486  (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
487  (int) *__i = 1
488  }
489  }
490 */
491 
492 SyntheticChildrenFrontEnd *
493 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(
494     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
495   static ConstString g_item_name;
496   if (!g_item_name)
497     g_item_name.SetCString("__i");
498   return (valobj_sp
499               ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name)
500               : nullptr);
501 }
502 
503 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
504     LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
505     : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(),
506       m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) {
507   if (valobj_sp)
508     Update();
509 }
510 
511 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
512     CalculateNumChildren() {
513   return (m_cntrl ? 1 : 0);
514 }
515 
516 lldb::ValueObjectSP
517 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(
518     size_t idx) {
519   if (!m_cntrl)
520     return lldb::ValueObjectSP();
521 
522   ValueObjectSP valobj_sp = m_backend.GetSP();
523   if (!valobj_sp)
524     return lldb::ValueObjectSP();
525 
526   if (idx == 0)
527     return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true);
528 
529   if (idx > 2)
530     return lldb::ValueObjectSP();
531 
532   if (idx == 1) {
533     if (!m_count_sp) {
534       ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName(
535           ConstString("__shared_owners_"), true));
536       if (!shared_owners_sp)
537         return lldb::ValueObjectSP();
538       uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0);
539       DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
540       m_count_sp = CreateValueObjectFromData(
541           "count", data, valobj_sp->GetExecutionContextRef(),
542           shared_owners_sp->GetCompilerType());
543     }
544     return m_count_sp;
545   } else /* if (idx == 2) */
546   {
547     if (!m_weak_count_sp) {
548       ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName(
549           ConstString("__shared_weak_owners_"), true));
550       if (!shared_weak_owners_sp)
551         return lldb::ValueObjectSP();
552       uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0);
553       DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
554       m_weak_count_sp = CreateValueObjectFromData(
555           "count", data, valobj_sp->GetExecutionContextRef(),
556           shared_weak_owners_sp->GetCompilerType());
557     }
558     return m_weak_count_sp;
559   }
560 }
561 
562 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {
563   m_count_sp.reset();
564   m_weak_count_sp.reset();
565   m_cntrl = nullptr;
566 
567   ValueObjectSP valobj_sp = m_backend.GetSP();
568   if (!valobj_sp)
569     return false;
570 
571   TargetSP target_sp(valobj_sp->GetTargetSP());
572   if (!target_sp)
573     return false;
574 
575   m_byte_order = target_sp->GetArchitecture().GetByteOrder();
576   m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize();
577 
578   lldb::ValueObjectSP cntrl_sp(
579       valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true));
580 
581   m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular
582                             // dependency
583   return false;
584 }
585 
586 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
587     MightHaveChildren() {
588   return true;
589 }
590 
591 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
592     GetIndexOfChildWithName(const ConstString &name) {
593   if (name == ConstString("__ptr_"))
594     return 0;
595   if (name == ConstString("count"))
596     return 1;
597   if (name == ConstString("weak_count"))
598     return 2;
599   return UINT32_MAX;
600 }
601 
602 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
603     ~LibcxxSharedPtrSyntheticFrontEnd() = default;
604 
605 SyntheticChildrenFrontEnd *
606 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(
607     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
608   return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)
609                     : nullptr);
610 }
611 
612 bool lldb_private::formatters::LibcxxContainerSummaryProvider(
613     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
614   if (valobj.IsPointerType()) {
615     uint64_t value = valobj.GetValueAsUnsigned(0);
616     if (!value)
617       return false;
618     stream.Printf("0x%016" PRIx64 " ", value);
619   }
620   return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr,
621                                        nullptr, nullptr, &valobj, false, false);
622 }
623 
624 // the field layout in a libc++ string (cap, side, data or data, size, cap)
625 enum LibcxxStringLayoutMode {
626   eLibcxxStringLayoutModeCSD = 0,
627   eLibcxxStringLayoutModeDSC = 1,
628   eLibcxxStringLayoutModeInvalid = 0xffff
629 };
630 
631 // this function abstracts away the layout and mode details of a libc++ string
632 // and returns the address of the data and the size ready for callers to
633 // consume
634 static bool ExtractLibcxxStringInfo(ValueObject &valobj,
635                                     ValueObjectSP &location_sp,
636                                     uint64_t &size) {
637   ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0}));
638   if (!D)
639     return false;
640 
641   ValueObjectSP layout_decider(
642     D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0})));
643 
644   // this child should exist
645   if (!layout_decider)
646     return false;
647 
648   ConstString g_data_name("__data_");
649   ConstString g_size_name("__size_");
650   bool short_mode = false; // this means the string is in short-mode and the
651                            // data is stored inline
652   LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name)
653                                       ? eLibcxxStringLayoutModeDSC
654                                       : eLibcxxStringLayoutModeCSD;
655   uint64_t size_mode_value = 0;
656 
657   if (layout == eLibcxxStringLayoutModeDSC) {
658     ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0}));
659     if (!size_mode)
660       return false;
661 
662     if (size_mode->GetName() != g_size_name) {
663       // we are hitting the padding structure, move along
664       size_mode = D->GetChildAtIndexPath({1, 1, 1});
665       if (!size_mode)
666         return false;
667     }
668 
669     size_mode_value = (size_mode->GetValueAsUnsigned(0));
670     short_mode = ((size_mode_value & 0x80) == 0);
671   } else {
672     ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0}));
673     if (!size_mode)
674       return false;
675 
676     size_mode_value = (size_mode->GetValueAsUnsigned(0));
677     short_mode = ((size_mode_value & 1) == 0);
678   }
679 
680   if (short_mode) {
681     ValueObjectSP s(D->GetChildAtIndex(1, true));
682     if (!s)
683       return false;
684     location_sp = s->GetChildAtIndex(
685         (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true);
686     size = (layout == eLibcxxStringLayoutModeDSC)
687                ? size_mode_value
688                : ((size_mode_value >> 1) % 256);
689     return (location_sp.get() != nullptr);
690   } else {
691     ValueObjectSP l(D->GetChildAtIndex(0, true));
692     if (!l)
693       return false;
694     // we can use the layout_decider object as the data pointer
695     location_sp = (layout == eLibcxxStringLayoutModeDSC)
696                       ? layout_decider
697                       : l->GetChildAtIndex(2, true);
698     ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
699     if (!size_vo || !location_sp)
700       return false;
701     size = size_vo->GetValueAsUnsigned(0);
702     return true;
703   }
704 }
705 
706 bool lldb_private::formatters::LibcxxWStringSummaryProvider(
707     ValueObject &valobj, Stream &stream,
708     const TypeSummaryOptions &summary_options) {
709   uint64_t size = 0;
710   ValueObjectSP location_sp;
711   if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
712     return false;
713   if (size == 0) {
714     stream.Printf("L\"\"");
715     return true;
716   }
717   if (!location_sp)
718     return false;
719 
720   DataExtractor extractor;
721 
722   StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
723 
724   if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
725     const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
726     if (size > max_size) {
727       size = max_size;
728       options.SetIsTruncated(true);
729     }
730   }
731   location_sp->GetPointeeData(extractor, 0, size);
732 
733   // std::wstring::size() is measured in 'characters', not bytes
734   auto wchar_t_size = valobj.GetTargetSP()
735                           ->GetScratchClangASTContext()
736                           ->GetBasicType(lldb::eBasicTypeWChar)
737                           .GetByteSize(nullptr);
738 
739   options.SetData(extractor);
740   options.SetStream(&stream);
741   options.SetPrefixToken("L");
742   options.SetQuote('"');
743   options.SetSourceSize(size);
744   options.SetBinaryZeroIsTerminator(false);
745 
746   switch (wchar_t_size) {
747   case 1:
748     StringPrinter::ReadBufferAndDumpToStream<
749         lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
750         options);
751     break;
752 
753   case 2:
754     lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<
755         lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
756         options);
757     break;
758 
759   case 4:
760     lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<
761         lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
762         options);
763     break;
764 
765   default:
766     stream.Printf("size for wchar_t is not valid");
767     return true;
768   }
769 
770   return true;
771 }
772 
773 bool lldb_private::formatters::LibcxxStringSummaryProvider(
774     ValueObject &valobj, Stream &stream,
775     const TypeSummaryOptions &summary_options) {
776   uint64_t size = 0;
777   ValueObjectSP location_sp;
778 
779   if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
780     return false;
781 
782   if (size == 0) {
783     stream.Printf("\"\"");
784     return true;
785   }
786 
787   if (!location_sp)
788     return false;
789 
790   StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
791 
792   DataExtractor extractor;
793   if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
794     const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
795     if (size > max_size) {
796       size = max_size;
797       options.SetIsTruncated(true);
798     }
799   }
800   location_sp->GetPointeeData(extractor, 0, size);
801 
802   options.SetData(extractor);
803   options.SetStream(&stream);
804   options.SetPrefixToken(nullptr);
805   options.SetQuote('"');
806   options.SetSourceSize(size);
807   options.SetBinaryZeroIsTerminator(false);
808   StringPrinter::ReadBufferAndDumpToStream<
809       StringPrinter::StringElementType::ASCII>(options);
810 
811   return true;
812 }
813