xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- LibCxx.cpp --------------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "LibCxx.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Core/Debugger.h"
12061da546Spatrick #include "lldb/Core/FormatEntity.h"
13061da546Spatrick #include "lldb/Core/ValueObject.h"
14061da546Spatrick #include "lldb/Core/ValueObjectConstResult.h"
15061da546Spatrick #include "lldb/DataFormatters/FormattersHelpers.h"
16061da546Spatrick #include "lldb/DataFormatters/StringPrinter.h"
17061da546Spatrick #include "lldb/DataFormatters/TypeSummary.h"
18061da546Spatrick #include "lldb/DataFormatters/VectorIterator.h"
19061da546Spatrick #include "lldb/Target/ProcessStructReader.h"
20061da546Spatrick #include "lldb/Target/SectionLoadList.h"
21061da546Spatrick #include "lldb/Target/Target.h"
22*f6aab3d8Srobert #include "lldb/Utility/ConstString.h"
23061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
24061da546Spatrick #include "lldb/Utility/Endian.h"
25061da546Spatrick #include "lldb/Utility/Status.h"
26061da546Spatrick #include "lldb/Utility/Stream.h"
27061da546Spatrick 
28061da546Spatrick #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
29dda28197Spatrick #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
30*f6aab3d8Srobert #include "lldb/lldb-enumerations.h"
31*f6aab3d8Srobert #include <optional>
32*f6aab3d8Srobert #include <tuple>
33061da546Spatrick 
34061da546Spatrick using namespace lldb;
35061da546Spatrick using namespace lldb_private;
36061da546Spatrick using namespace lldb_private::formatters;
37061da546Spatrick 
GetChildMemberWithName(ValueObject & obj,llvm::ArrayRef<ConstString> alternative_names)38*f6aab3d8Srobert lldb::ValueObjectSP lldb_private::formatters::GetChildMemberWithName(
39*f6aab3d8Srobert     ValueObject &obj, llvm::ArrayRef<ConstString> alternative_names) {
40*f6aab3d8Srobert   for (ConstString name : alternative_names) {
41*f6aab3d8Srobert     lldb::ValueObjectSP child_sp = obj.GetChildMemberWithName(name, true);
42*f6aab3d8Srobert 
43*f6aab3d8Srobert     if (child_sp)
44*f6aab3d8Srobert       return child_sp;
45*f6aab3d8Srobert   }
46*f6aab3d8Srobert   return {};
47*f6aab3d8Srobert }
48*f6aab3d8Srobert 
LibcxxOptionalSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)49061da546Spatrick bool lldb_private::formatters::LibcxxOptionalSummaryProvider(
50061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
51061da546Spatrick   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
52061da546Spatrick   if (!valobj_sp)
53061da546Spatrick     return false;
54061da546Spatrick 
55061da546Spatrick   // An optional either contains a value or not, the member __engaged_ is
56061da546Spatrick   // a bool flag, it is true if the optional has a value and false otherwise.
57061da546Spatrick   ValueObjectSP engaged_sp(
58061da546Spatrick       valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true));
59061da546Spatrick 
60061da546Spatrick   if (!engaged_sp)
61061da546Spatrick     return false;
62061da546Spatrick 
63061da546Spatrick   llvm::StringRef engaged_as_cstring(
64061da546Spatrick       engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false");
65061da546Spatrick 
66061da546Spatrick   stream.Printf(" Has Value=%s ", engaged_as_cstring.data());
67061da546Spatrick 
68061da546Spatrick   return true;
69061da546Spatrick }
70061da546Spatrick 
LibcxxFunctionSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)71061da546Spatrick bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
72061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
73061da546Spatrick 
74061da546Spatrick   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
75061da546Spatrick 
76061da546Spatrick   if (!valobj_sp)
77061da546Spatrick     return false;
78061da546Spatrick 
79061da546Spatrick   ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
80061da546Spatrick   Process *process = exe_ctx.GetProcessPtr();
81061da546Spatrick 
82061da546Spatrick   if (process == nullptr)
83061da546Spatrick     return false;
84061da546Spatrick 
85061da546Spatrick   CPPLanguageRuntime *cpp_runtime = CPPLanguageRuntime::Get(*process);
86061da546Spatrick 
87061da546Spatrick   if (!cpp_runtime)
88061da546Spatrick     return false;
89061da546Spatrick 
90061da546Spatrick   CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =
91061da546Spatrick       cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp);
92061da546Spatrick 
93061da546Spatrick   switch (callable_info.callable_case) {
94061da546Spatrick   case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid:
95*f6aab3d8Srobert     stream.Printf(" __f_ = %" PRIu64, callable_info.member_f_pointer_value);
96061da546Spatrick     return false;
97061da546Spatrick     break;
98061da546Spatrick   case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda:
99061da546Spatrick     stream.Printf(
100061da546Spatrick         " Lambda in File %s at Line %u",
101061da546Spatrick         callable_info.callable_line_entry.file.GetFilename().GetCString(),
102061da546Spatrick         callable_info.callable_line_entry.line);
103061da546Spatrick     break;
104061da546Spatrick   case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject:
105061da546Spatrick     stream.Printf(
106061da546Spatrick         " Function in File %s at Line %u",
107061da546Spatrick         callable_info.callable_line_entry.file.GetFilename().GetCString(),
108061da546Spatrick         callable_info.callable_line_entry.line);
109061da546Spatrick     break;
110061da546Spatrick   case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction:
111061da546Spatrick     stream.Printf(" Function = %s ",
112061da546Spatrick                   callable_info.callable_symbol.GetName().GetCString());
113061da546Spatrick     break;
114061da546Spatrick   }
115061da546Spatrick 
116061da546Spatrick   return true;
117061da546Spatrick }
118061da546Spatrick 
LibcxxSmartPointerSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)119061da546Spatrick bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
120061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
121061da546Spatrick   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
122061da546Spatrick   if (!valobj_sp)
123061da546Spatrick     return false;
124061da546Spatrick   ValueObjectSP ptr_sp(
125061da546Spatrick       valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
126061da546Spatrick   ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath(
127061da546Spatrick       {ConstString("__cntrl_"), ConstString("__shared_owners_")}));
128061da546Spatrick   ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath(
129061da546Spatrick       {ConstString("__cntrl_"), ConstString("__shared_weak_owners_")}));
130061da546Spatrick 
131061da546Spatrick   if (!ptr_sp)
132061da546Spatrick     return false;
133061da546Spatrick 
134061da546Spatrick   if (ptr_sp->GetValueAsUnsigned(0) == 0) {
135061da546Spatrick     stream.Printf("nullptr");
136061da546Spatrick     return true;
137061da546Spatrick   } else {
138061da546Spatrick     bool print_pointee = false;
139061da546Spatrick     Status error;
140061da546Spatrick     ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
141061da546Spatrick     if (pointee_sp && error.Success()) {
142061da546Spatrick       if (pointee_sp->DumpPrintableRepresentation(
143061da546Spatrick               stream, ValueObject::eValueObjectRepresentationStyleSummary,
144061da546Spatrick               lldb::eFormatInvalid,
145061da546Spatrick               ValueObject::PrintableRepresentationSpecialCases::eDisable,
146061da546Spatrick               false))
147061da546Spatrick         print_pointee = true;
148061da546Spatrick     }
149061da546Spatrick     if (!print_pointee)
150061da546Spatrick       stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
151061da546Spatrick   }
152061da546Spatrick 
153061da546Spatrick   if (count_sp)
154061da546Spatrick     stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0));
155061da546Spatrick 
156061da546Spatrick   if (weakcount_sp)
157061da546Spatrick     stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0));
158061da546Spatrick 
159061da546Spatrick   return true;
160061da546Spatrick }
161061da546Spatrick 
LibcxxUniquePointerSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)162dda28197Spatrick bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
163dda28197Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
164dda28197Spatrick   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
165dda28197Spatrick   if (!valobj_sp)
166dda28197Spatrick     return false;
167dda28197Spatrick 
168dda28197Spatrick   ValueObjectSP ptr_sp(
169dda28197Spatrick       valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
170dda28197Spatrick   if (!ptr_sp)
171dda28197Spatrick     return false;
172dda28197Spatrick 
173dda28197Spatrick   ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp);
174dda28197Spatrick   if (!ptr_sp)
175dda28197Spatrick     return false;
176dda28197Spatrick 
177dda28197Spatrick   if (ptr_sp->GetValueAsUnsigned(0) == 0) {
178dda28197Spatrick     stream.Printf("nullptr");
179dda28197Spatrick     return true;
180dda28197Spatrick   } else {
181dda28197Spatrick     bool print_pointee = false;
182dda28197Spatrick     Status error;
183dda28197Spatrick     ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
184dda28197Spatrick     if (pointee_sp && error.Success()) {
185dda28197Spatrick       if (pointee_sp->DumpPrintableRepresentation(
186dda28197Spatrick               stream, ValueObject::eValueObjectRepresentationStyleSummary,
187dda28197Spatrick               lldb::eFormatInvalid,
188dda28197Spatrick               ValueObject::PrintableRepresentationSpecialCases::eDisable,
189dda28197Spatrick               false))
190dda28197Spatrick         print_pointee = true;
191dda28197Spatrick     }
192dda28197Spatrick     if (!print_pointee)
193dda28197Spatrick       stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
194dda28197Spatrick   }
195dda28197Spatrick 
196dda28197Spatrick   return true;
197dda28197Spatrick }
198dda28197Spatrick 
199061da546Spatrick /*
200061da546Spatrick  (lldb) fr var ibeg --raw --ptr-depth 1
201061da546Spatrick  (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int,
202061da546Spatrick  std::__1::basic_string<char, std::__1::char_traits<char>,
203061da546Spatrick  std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int,
204061da546Spatrick  std::__1::basic_string<char, std::__1::char_traits<char>,
205061da546Spatrick  std::__1::allocator<char> > >, void *> *, long> >) ibeg = {
206061da546Spatrick  __i_ = {
207061da546Spatrick  __ptr_ = 0x0000000100103870 {
208061da546Spatrick  std::__1::__tree_node_base<void *> = {
209061da546Spatrick  std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = {
210061da546Spatrick  __left_ = 0x0000000000000000
211061da546Spatrick  }
212061da546Spatrick  __right_ = 0x0000000000000000
213061da546Spatrick  __parent_ = 0x00000001001038b0
214061da546Spatrick  __is_black_ = true
215061da546Spatrick  }
216061da546Spatrick  __value_ = {
217061da546Spatrick  first = 0
218061da546Spatrick  second = { std::string }
219061da546Spatrick  */
220061da546Spatrick 
221061da546Spatrick lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)222061da546Spatrick     LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
223061da546Spatrick     : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() {
224061da546Spatrick   if (valobj_sp)
225061da546Spatrick     Update();
226061da546Spatrick }
227061da546Spatrick 
Update()228061da546Spatrick bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
229061da546Spatrick   m_pair_sp.reset();
230061da546Spatrick   m_pair_ptr = nullptr;
231061da546Spatrick 
232061da546Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
233061da546Spatrick   if (!valobj_sp)
234061da546Spatrick     return false;
235061da546Spatrick 
236061da546Spatrick   TargetSP target_sp(valobj_sp->GetTargetSP());
237061da546Spatrick 
238061da546Spatrick   if (!target_sp)
239061da546Spatrick     return false;
240061da546Spatrick 
241061da546Spatrick   if (!valobj_sp)
242061da546Spatrick     return false;
243061da546Spatrick 
244*f6aab3d8Srobert   static ConstString g_i_("__i_");
245061da546Spatrick 
246061da546Spatrick   // this must be a ValueObject* because it is a child of the ValueObject we
247061da546Spatrick   // are producing children for it if were a ValueObjectSP, we would end up
248061da546Spatrick   // with a loop (iterator -> synthetic -> child -> parent == iterator) and
249061da546Spatrick   // that would in turn leak memory by never allowing the ValueObjects to die
250061da546Spatrick   // and free their memory
251061da546Spatrick   m_pair_ptr = valobj_sp
252061da546Spatrick                    ->GetValueForExpressionPath(
253061da546Spatrick                        ".__i_.__ptr_->__value_", nullptr, nullptr,
254061da546Spatrick                        ValueObject::GetValueForExpressionPathOptions()
255061da546Spatrick                            .DontCheckDotVsArrowSyntax()
256061da546Spatrick                            .SetSyntheticChildrenTraversal(
257061da546Spatrick                                ValueObject::GetValueForExpressionPathOptions::
258061da546Spatrick                                    SyntheticChildrenTraversal::None),
259061da546Spatrick                        nullptr)
260061da546Spatrick                    .get();
261061da546Spatrick 
262061da546Spatrick   if (!m_pair_ptr) {
263061da546Spatrick     m_pair_ptr = valobj_sp
264061da546Spatrick                      ->GetValueForExpressionPath(
265061da546Spatrick                          ".__i_.__ptr_", nullptr, nullptr,
266061da546Spatrick                          ValueObject::GetValueForExpressionPathOptions()
267061da546Spatrick                              .DontCheckDotVsArrowSyntax()
268061da546Spatrick                              .SetSyntheticChildrenTraversal(
269061da546Spatrick                                  ValueObject::GetValueForExpressionPathOptions::
270061da546Spatrick                                      SyntheticChildrenTraversal::None),
271061da546Spatrick                          nullptr)
272061da546Spatrick                      .get();
273061da546Spatrick     if (m_pair_ptr) {
274*f6aab3d8Srobert       auto __i_(valobj_sp->GetChildMemberWithName(g_i_, true));
275061da546Spatrick       if (!__i_) {
276061da546Spatrick         m_pair_ptr = nullptr;
277061da546Spatrick         return false;
278061da546Spatrick       }
279061da546Spatrick       CompilerType pair_type(
280061da546Spatrick           __i_->GetCompilerType().GetTypeTemplateArgument(0));
281061da546Spatrick       std::string name;
282061da546Spatrick       uint64_t bit_offset_ptr;
283061da546Spatrick       uint32_t bitfield_bit_size_ptr;
284061da546Spatrick       bool is_bitfield_ptr;
285061da546Spatrick       pair_type = pair_type.GetFieldAtIndex(
286061da546Spatrick           0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
287061da546Spatrick       if (!pair_type) {
288061da546Spatrick         m_pair_ptr = nullptr;
289061da546Spatrick         return false;
290061da546Spatrick       }
291061da546Spatrick 
292061da546Spatrick       auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS));
293061da546Spatrick       m_pair_ptr = nullptr;
294061da546Spatrick       if (addr && addr != LLDB_INVALID_ADDRESS) {
295*f6aab3d8Srobert         auto ts = pair_type.GetTypeSystem();
296*f6aab3d8Srobert         auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>();
297061da546Spatrick         if (!ast_ctx)
298061da546Spatrick           return false;
299*f6aab3d8Srobert 
300*f6aab3d8Srobert         // Mimick layout of std::__tree_iterator::__ptr_ and read it in
301*f6aab3d8Srobert         // from process memory.
302*f6aab3d8Srobert         //
303*f6aab3d8Srobert         // The following shows the contiguous block of memory:
304*f6aab3d8Srobert         //
305*f6aab3d8Srobert         //        +-----------------------------+ class __tree_end_node
306*f6aab3d8Srobert         // __ptr_ | pointer __left_;            |
307*f6aab3d8Srobert         //        +-----------------------------+ class __tree_node_base
308*f6aab3d8Srobert         //        | pointer __right_;           |
309*f6aab3d8Srobert         //        | __parent_pointer __parent_; |
310*f6aab3d8Srobert         //        | bool __is_black_;           |
311*f6aab3d8Srobert         //        +-----------------------------+ class __tree_node
312*f6aab3d8Srobert         //        | __node_value_type __value_; | <<< our key/value pair
313*f6aab3d8Srobert         //        +-----------------------------+
314*f6aab3d8Srobert         //
315061da546Spatrick         CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
316061da546Spatrick             ConstString(),
317061da546Spatrick             {{"ptr0",
318061da546Spatrick               ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
319061da546Spatrick              {"ptr1",
320061da546Spatrick               ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
321061da546Spatrick              {"ptr2",
322061da546Spatrick               ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
323061da546Spatrick              {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
324061da546Spatrick              {"payload", pair_type}});
325*f6aab3d8Srobert         std::optional<uint64_t> size = tree_node_type.GetByteSize(nullptr);
326061da546Spatrick         if (!size)
327061da546Spatrick           return false;
328*f6aab3d8Srobert         WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
329061da546Spatrick         ProcessSP process_sp(target_sp->GetProcessSP());
330061da546Spatrick         Status error;
331061da546Spatrick         process_sp->ReadMemory(addr, buffer_sp->GetBytes(),
332061da546Spatrick                                buffer_sp->GetByteSize(), error);
333061da546Spatrick         if (error.Fail())
334061da546Spatrick           return false;
335061da546Spatrick         DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(),
336061da546Spatrick                                 process_sp->GetAddressByteSize());
337061da546Spatrick         auto pair_sp = CreateValueObjectFromData(
338061da546Spatrick             "pair", extractor, valobj_sp->GetExecutionContextRef(),
339061da546Spatrick             tree_node_type);
340061da546Spatrick         if (pair_sp)
341061da546Spatrick           m_pair_sp = pair_sp->GetChildAtIndex(4, true);
342061da546Spatrick       }
343061da546Spatrick     }
344061da546Spatrick   }
345061da546Spatrick 
346061da546Spatrick   return false;
347061da546Spatrick }
348061da546Spatrick 
349061da546Spatrick size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
CalculateNumChildren()350061da546Spatrick     CalculateNumChildren() {
351061da546Spatrick   return 2;
352061da546Spatrick }
353061da546Spatrick 
354061da546Spatrick lldb::ValueObjectSP
GetChildAtIndex(size_t idx)355061da546Spatrick lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex(
356061da546Spatrick     size_t idx) {
357061da546Spatrick   if (m_pair_ptr)
358061da546Spatrick     return m_pair_ptr->GetChildAtIndex(idx, true);
359061da546Spatrick   if (m_pair_sp)
360061da546Spatrick     return m_pair_sp->GetChildAtIndex(idx, true);
361061da546Spatrick   return lldb::ValueObjectSP();
362061da546Spatrick }
363061da546Spatrick 
364061da546Spatrick bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
MightHaveChildren()365061da546Spatrick     MightHaveChildren() {
366061da546Spatrick   return true;
367061da546Spatrick }
368061da546Spatrick 
369061da546Spatrick size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)370061da546Spatrick     GetIndexOfChildWithName(ConstString name) {
371061da546Spatrick   if (name == "first")
372061da546Spatrick     return 0;
373061da546Spatrick   if (name == "second")
374061da546Spatrick     return 1;
375061da546Spatrick   return UINT32_MAX;
376061da546Spatrick }
377061da546Spatrick 
378061da546Spatrick lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
~LibCxxMapIteratorSyntheticFrontEnd()379061da546Spatrick     ~LibCxxMapIteratorSyntheticFrontEnd() {
380061da546Spatrick   // this will be deleted when its parent dies (since it's a child object)
381061da546Spatrick   // delete m_pair_ptr;
382061da546Spatrick }
383061da546Spatrick 
384061da546Spatrick SyntheticChildrenFrontEnd *
LibCxxMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)385061da546Spatrick lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator(
386061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
387061da546Spatrick   return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp)
388061da546Spatrick                     : nullptr);
389061da546Spatrick }
390061da546Spatrick 
391*f6aab3d8Srobert lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)392*f6aab3d8Srobert     LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
393*f6aab3d8Srobert     : SyntheticChildrenFrontEnd(*valobj_sp) {
394*f6aab3d8Srobert   if (valobj_sp)
395*f6aab3d8Srobert     Update();
396*f6aab3d8Srobert }
397*f6aab3d8Srobert 
398*f6aab3d8Srobert bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
Update()399*f6aab3d8Srobert     Update() {
400*f6aab3d8Srobert   m_pair_sp.reset();
401*f6aab3d8Srobert   m_iter_ptr = nullptr;
402*f6aab3d8Srobert 
403*f6aab3d8Srobert   ValueObjectSP valobj_sp = m_backend.GetSP();
404*f6aab3d8Srobert   if (!valobj_sp)
405*f6aab3d8Srobert     return false;
406*f6aab3d8Srobert 
407*f6aab3d8Srobert   TargetSP target_sp(valobj_sp->GetTargetSP());
408*f6aab3d8Srobert 
409*f6aab3d8Srobert   if (!target_sp)
410*f6aab3d8Srobert     return false;
411*f6aab3d8Srobert 
412*f6aab3d8Srobert   if (!valobj_sp)
413*f6aab3d8Srobert     return false;
414*f6aab3d8Srobert 
415*f6aab3d8Srobert   auto exprPathOptions = ValueObject::GetValueForExpressionPathOptions()
416*f6aab3d8Srobert                              .DontCheckDotVsArrowSyntax()
417*f6aab3d8Srobert                              .SetSyntheticChildrenTraversal(
418*f6aab3d8Srobert                                  ValueObject::GetValueForExpressionPathOptions::
419*f6aab3d8Srobert                                      SyntheticChildrenTraversal::None);
420*f6aab3d8Srobert 
421*f6aab3d8Srobert   // This must be a ValueObject* because it is a child of the ValueObject we
422*f6aab3d8Srobert   // are producing children for it if were a ValueObjectSP, we would end up
423*f6aab3d8Srobert   // with a loop (iterator -> synthetic -> child -> parent == iterator) and
424*f6aab3d8Srobert   // that would in turn leak memory by never allowing the ValueObjects to die
425*f6aab3d8Srobert   // and free their memory.
426*f6aab3d8Srobert   m_iter_ptr =
427*f6aab3d8Srobert       valobj_sp
428*f6aab3d8Srobert           ->GetValueForExpressionPath(".__i_.__node_", nullptr, nullptr,
429*f6aab3d8Srobert                                       exprPathOptions, nullptr)
430*f6aab3d8Srobert           .get();
431*f6aab3d8Srobert 
432*f6aab3d8Srobert   if (m_iter_ptr) {
433*f6aab3d8Srobert     auto iter_child(
434*f6aab3d8Srobert         valobj_sp->GetChildMemberWithName(ConstString("__i_"), true));
435*f6aab3d8Srobert     if (!iter_child) {
436*f6aab3d8Srobert       m_iter_ptr = nullptr;
437*f6aab3d8Srobert       return false;
438*f6aab3d8Srobert     }
439*f6aab3d8Srobert 
440*f6aab3d8Srobert     CompilerType node_type(iter_child->GetCompilerType()
441*f6aab3d8Srobert                                .GetTypeTemplateArgument(0)
442*f6aab3d8Srobert                                .GetPointeeType());
443*f6aab3d8Srobert 
444*f6aab3d8Srobert     CompilerType pair_type(node_type.GetTypeTemplateArgument(0));
445*f6aab3d8Srobert 
446*f6aab3d8Srobert     std::string name;
447*f6aab3d8Srobert     uint64_t bit_offset_ptr;
448*f6aab3d8Srobert     uint32_t bitfield_bit_size_ptr;
449*f6aab3d8Srobert     bool is_bitfield_ptr;
450*f6aab3d8Srobert 
451*f6aab3d8Srobert     pair_type = pair_type.GetFieldAtIndex(
452*f6aab3d8Srobert         0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
453*f6aab3d8Srobert     if (!pair_type) {
454*f6aab3d8Srobert       m_iter_ptr = nullptr;
455*f6aab3d8Srobert       return false;
456*f6aab3d8Srobert     }
457*f6aab3d8Srobert 
458*f6aab3d8Srobert     uint64_t addr = m_iter_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
459*f6aab3d8Srobert     m_iter_ptr = nullptr;
460*f6aab3d8Srobert 
461*f6aab3d8Srobert     if (addr == 0 || addr == LLDB_INVALID_ADDRESS)
462*f6aab3d8Srobert       return false;
463*f6aab3d8Srobert 
464*f6aab3d8Srobert     auto ts = pair_type.GetTypeSystem();
465*f6aab3d8Srobert     auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>();
466*f6aab3d8Srobert     if (!ast_ctx)
467*f6aab3d8Srobert       return false;
468*f6aab3d8Srobert 
469*f6aab3d8Srobert     // Mimick layout of std::__hash_iterator::__node_ and read it in
470*f6aab3d8Srobert     // from process memory.
471*f6aab3d8Srobert     //
472*f6aab3d8Srobert     // The following shows the contiguous block of memory:
473*f6aab3d8Srobert     //
474*f6aab3d8Srobert     //         +-----------------------------+ class __hash_node_base
475*f6aab3d8Srobert     // __node_ | __next_pointer __next_;     |
476*f6aab3d8Srobert     //         +-----------------------------+ class __hash_node
477*f6aab3d8Srobert     //         | size_t __hash_;             |
478*f6aab3d8Srobert     //         | __node_value_type __value_; | <<< our key/value pair
479*f6aab3d8Srobert     //         +-----------------------------+
480*f6aab3d8Srobert     //
481*f6aab3d8Srobert     CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
482*f6aab3d8Srobert         ConstString(),
483*f6aab3d8Srobert         {{"__next_",
484*f6aab3d8Srobert           ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
485*f6aab3d8Srobert          {"__hash_", ast_ctx->GetBasicType(lldb::eBasicTypeUnsignedLongLong)},
486*f6aab3d8Srobert          {"__value_", pair_type}});
487*f6aab3d8Srobert     std::optional<uint64_t> size = tree_node_type.GetByteSize(nullptr);
488*f6aab3d8Srobert     if (!size)
489*f6aab3d8Srobert       return false;
490*f6aab3d8Srobert     WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
491*f6aab3d8Srobert     ProcessSP process_sp(target_sp->GetProcessSP());
492*f6aab3d8Srobert     Status error;
493*f6aab3d8Srobert     process_sp->ReadMemory(addr, buffer_sp->GetBytes(),
494*f6aab3d8Srobert                            buffer_sp->GetByteSize(), error);
495*f6aab3d8Srobert     if (error.Fail())
496*f6aab3d8Srobert       return false;
497*f6aab3d8Srobert     DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(),
498*f6aab3d8Srobert                             process_sp->GetAddressByteSize());
499*f6aab3d8Srobert     auto pair_sp = CreateValueObjectFromData(
500*f6aab3d8Srobert         "pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type);
501*f6aab3d8Srobert     if (pair_sp)
502*f6aab3d8Srobert       m_pair_sp = pair_sp->GetChildAtIndex(2, true);
503*f6aab3d8Srobert   }
504*f6aab3d8Srobert 
505*f6aab3d8Srobert   return false;
506*f6aab3d8Srobert }
507*f6aab3d8Srobert 
508*f6aab3d8Srobert size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
CalculateNumChildren()509*f6aab3d8Srobert     CalculateNumChildren() {
510*f6aab3d8Srobert   return 2;
511*f6aab3d8Srobert }
512*f6aab3d8Srobert 
513*f6aab3d8Srobert lldb::ValueObjectSP lldb_private::formatters::
GetChildAtIndex(size_t idx)514*f6aab3d8Srobert     LibCxxUnorderedMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
515*f6aab3d8Srobert   if (m_pair_sp)
516*f6aab3d8Srobert     return m_pair_sp->GetChildAtIndex(idx, true);
517*f6aab3d8Srobert   return lldb::ValueObjectSP();
518*f6aab3d8Srobert }
519*f6aab3d8Srobert 
520*f6aab3d8Srobert bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
MightHaveChildren()521*f6aab3d8Srobert     MightHaveChildren() {
522*f6aab3d8Srobert   return true;
523*f6aab3d8Srobert }
524*f6aab3d8Srobert 
525*f6aab3d8Srobert size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)526*f6aab3d8Srobert     GetIndexOfChildWithName(ConstString name) {
527*f6aab3d8Srobert   if (name == "first")
528*f6aab3d8Srobert     return 0;
529*f6aab3d8Srobert   if (name == "second")
530*f6aab3d8Srobert     return 1;
531*f6aab3d8Srobert   return UINT32_MAX;
532*f6aab3d8Srobert }
533*f6aab3d8Srobert 
534*f6aab3d8Srobert SyntheticChildrenFrontEnd *
LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)535*f6aab3d8Srobert lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(
536*f6aab3d8Srobert     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
537*f6aab3d8Srobert   return (valobj_sp ? new LibCxxUnorderedMapIteratorSyntheticFrontEnd(valobj_sp)
538*f6aab3d8Srobert                     : nullptr);
539*f6aab3d8Srobert }
540*f6aab3d8Srobert 
541061da546Spatrick /*
542061da546Spatrick  (lldb) fr var ibeg --raw --ptr-depth 1 -T
543061da546Spatrick  (std::__1::__wrap_iter<int *>) ibeg = {
544061da546Spatrick  (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
545061da546Spatrick  (int) *__i = 1
546061da546Spatrick  }
547061da546Spatrick  }
548061da546Spatrick */
549061da546Spatrick 
550061da546Spatrick SyntheticChildrenFrontEnd *
LibCxxVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)551061da546Spatrick lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(
552061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
553*f6aab3d8Srobert   return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
554*f6aab3d8Srobert                           valobj_sp, {ConstString("__i_"), ConstString("__i")})
555061da546Spatrick                     : nullptr);
556061da546Spatrick }
557061da546Spatrick 
558061da546Spatrick lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)559061da546Spatrick     LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
560be691f3bSpatrick     : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr) {
561061da546Spatrick   if (valobj_sp)
562061da546Spatrick     Update();
563061da546Spatrick }
564061da546Spatrick 
565061da546Spatrick size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
CalculateNumChildren()566061da546Spatrick     CalculateNumChildren() {
567061da546Spatrick   return (m_cntrl ? 1 : 0);
568061da546Spatrick }
569061da546Spatrick 
570061da546Spatrick lldb::ValueObjectSP
GetChildAtIndex(size_t idx)571061da546Spatrick lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(
572061da546Spatrick     size_t idx) {
573061da546Spatrick   if (!m_cntrl)
574061da546Spatrick     return lldb::ValueObjectSP();
575061da546Spatrick 
576061da546Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
577061da546Spatrick   if (!valobj_sp)
578061da546Spatrick     return lldb::ValueObjectSP();
579061da546Spatrick 
580061da546Spatrick   if (idx == 0)
581061da546Spatrick     return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true);
582061da546Spatrick 
583061da546Spatrick   if (idx == 1) {
584be691f3bSpatrick     if (auto ptr_sp =
585be691f3bSpatrick             valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)) {
586be691f3bSpatrick       Status status;
587be691f3bSpatrick       auto value_sp = ptr_sp->Dereference(status);
588be691f3bSpatrick       if (status.Success()) {
589be691f3bSpatrick         auto value_type_sp =
590be691f3bSpatrick             valobj_sp->GetCompilerType().GetTypeTemplateArgument(0);
591be691f3bSpatrick         return value_sp->Cast(value_type_sp);
592be691f3bSpatrick       }
593be691f3bSpatrick     }
594be691f3bSpatrick   }
595be691f3bSpatrick 
596061da546Spatrick   return lldb::ValueObjectSP();
597061da546Spatrick }
598061da546Spatrick 
Update()599061da546Spatrick bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {
600061da546Spatrick   m_cntrl = nullptr;
601061da546Spatrick 
602061da546Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
603061da546Spatrick   if (!valobj_sp)
604061da546Spatrick     return false;
605061da546Spatrick 
606061da546Spatrick   TargetSP target_sp(valobj_sp->GetTargetSP());
607061da546Spatrick   if (!target_sp)
608061da546Spatrick     return false;
609061da546Spatrick 
610061da546Spatrick   lldb::ValueObjectSP cntrl_sp(
611061da546Spatrick       valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true));
612061da546Spatrick 
613061da546Spatrick   m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular
614061da546Spatrick                             // dependency
615061da546Spatrick   return false;
616061da546Spatrick }
617061da546Spatrick 
618061da546Spatrick bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
MightHaveChildren()619061da546Spatrick     MightHaveChildren() {
620061da546Spatrick   return true;
621061da546Spatrick }
622061da546Spatrick 
623061da546Spatrick size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)624061da546Spatrick     GetIndexOfChildWithName(ConstString name) {
625061da546Spatrick   if (name == "__ptr_")
626061da546Spatrick     return 0;
627be691f3bSpatrick   if (name == "$$dereference$$")
628061da546Spatrick     return 1;
629061da546Spatrick   return UINT32_MAX;
630061da546Spatrick }
631061da546Spatrick 
632061da546Spatrick lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
633061da546Spatrick     ~LibcxxSharedPtrSyntheticFrontEnd() = default;
634061da546Spatrick 
635061da546Spatrick SyntheticChildrenFrontEnd *
LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)636061da546Spatrick lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(
637061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
638061da546Spatrick   return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)
639061da546Spatrick                     : nullptr);
640061da546Spatrick }
641061da546Spatrick 
642dda28197Spatrick lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)643dda28197Spatrick     LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
644be691f3bSpatrick     : SyntheticChildrenFrontEnd(*valobj_sp) {
645dda28197Spatrick   if (valobj_sp)
646dda28197Spatrick     Update();
647dda28197Spatrick }
648dda28197Spatrick 
649dda28197Spatrick lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
650dda28197Spatrick     ~LibcxxUniquePtrSyntheticFrontEnd() = default;
651dda28197Spatrick 
652dda28197Spatrick SyntheticChildrenFrontEnd *
LibcxxUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)653dda28197Spatrick lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator(
654dda28197Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
655dda28197Spatrick   return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp)
656dda28197Spatrick                     : nullptr);
657dda28197Spatrick }
658dda28197Spatrick 
659dda28197Spatrick size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
CalculateNumChildren()660dda28197Spatrick     CalculateNumChildren() {
661be691f3bSpatrick   return (m_value_ptr_sp ? 1 : 0);
662dda28197Spatrick }
663dda28197Spatrick 
664dda28197Spatrick lldb::ValueObjectSP
GetChildAtIndex(size_t idx)665dda28197Spatrick lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex(
666dda28197Spatrick     size_t idx) {
667be691f3bSpatrick   if (!m_value_ptr_sp)
668dda28197Spatrick     return lldb::ValueObjectSP();
669dda28197Spatrick 
670be691f3bSpatrick   if (idx == 0)
671be691f3bSpatrick     return m_value_ptr_sp;
672dda28197Spatrick 
673be691f3bSpatrick   if (idx == 1) {
674be691f3bSpatrick     Status status;
675be691f3bSpatrick     auto value_sp = m_value_ptr_sp->Dereference(status);
676be691f3bSpatrick     if (status.Success()) {
677be691f3bSpatrick       return value_sp;
678be691f3bSpatrick     }
679be691f3bSpatrick   }
680be691f3bSpatrick 
681be691f3bSpatrick   return lldb::ValueObjectSP();
682dda28197Spatrick }
683dda28197Spatrick 
Update()684dda28197Spatrick bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
685dda28197Spatrick   ValueObjectSP valobj_sp = m_backend.GetSP();
686dda28197Spatrick   if (!valobj_sp)
687dda28197Spatrick     return false;
688dda28197Spatrick 
689dda28197Spatrick   ValueObjectSP ptr_sp(
690dda28197Spatrick       valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
691dda28197Spatrick   if (!ptr_sp)
692dda28197Spatrick     return false;
693dda28197Spatrick 
694be691f3bSpatrick   m_value_ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp);
695dda28197Spatrick 
696dda28197Spatrick   return false;
697dda28197Spatrick }
698dda28197Spatrick 
699dda28197Spatrick bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
MightHaveChildren()700dda28197Spatrick     MightHaveChildren() {
701dda28197Spatrick   return true;
702dda28197Spatrick }
703dda28197Spatrick 
704dda28197Spatrick size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)705dda28197Spatrick     GetIndexOfChildWithName(ConstString name) {
706dda28197Spatrick   if (name == "__value_")
707dda28197Spatrick     return 0;
708be691f3bSpatrick   if (name == "$$dereference$$")
709be691f3bSpatrick     return 1;
710dda28197Spatrick   return UINT32_MAX;
711dda28197Spatrick }
712dda28197Spatrick 
LibcxxContainerSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)713061da546Spatrick bool lldb_private::formatters::LibcxxContainerSummaryProvider(
714061da546Spatrick     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
715061da546Spatrick   if (valobj.IsPointerType()) {
716061da546Spatrick     uint64_t value = valobj.GetValueAsUnsigned(0);
717061da546Spatrick     if (!value)
718061da546Spatrick       return false;
719061da546Spatrick     stream.Printf("0x%016" PRIx64 " ", value);
720061da546Spatrick   }
721061da546Spatrick   return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr,
722061da546Spatrick                                        nullptr, nullptr, &valobj, false, false);
723061da546Spatrick }
724061da546Spatrick 
725*f6aab3d8Srobert /// The field layout in a libc++ string (cap, side, data or data, size, cap).
726*f6aab3d8Srobert namespace {
727*f6aab3d8Srobert enum class StringLayout { CSD, DSC };
728*f6aab3d8Srobert }
729061da546Spatrick 
730dda28197Spatrick /// Determine the size in bytes of \p valobj (a libc++ std::string object) and
731dda28197Spatrick /// extract its data payload. Return the size + payload pair.
732*f6aab3d8Srobert // TODO: Support big-endian architectures.
733*f6aab3d8Srobert static std::optional<std::pair<uint64_t, ValueObjectSP>>
ExtractLibcxxStringInfo(ValueObject & valobj)734dda28197Spatrick ExtractLibcxxStringInfo(ValueObject &valobj) {
735*f6aab3d8Srobert   ValueObjectSP valobj_r_sp =
736*f6aab3d8Srobert       valobj.GetChildMemberWithName(ConstString("__r_"), /*can_create=*/true);
737*f6aab3d8Srobert   if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
738dda28197Spatrick     return {};
739061da546Spatrick 
740*f6aab3d8Srobert   // __r_ is a compressed_pair of the actual data and the allocator. The data we
741*f6aab3d8Srobert   // want is in the first base class.
742*f6aab3d8Srobert   ValueObjectSP valobj_r_base_sp =
743*f6aab3d8Srobert       valobj_r_sp->GetChildAtIndex(0, /*can_create=*/true);
744*f6aab3d8Srobert   if (!valobj_r_base_sp)
745dda28197Spatrick     return {};
746061da546Spatrick 
747*f6aab3d8Srobert   ValueObjectSP valobj_rep_sp = valobj_r_base_sp->GetChildMemberWithName(
748*f6aab3d8Srobert       ConstString("__value_"), /*can_create=*/true);
749*f6aab3d8Srobert   if (!valobj_rep_sp)
750*f6aab3d8Srobert     return {};
751*f6aab3d8Srobert 
752*f6aab3d8Srobert   ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName(ConstString("__l"),
753*f6aab3d8Srobert                                                           /*can_create=*/true);
754*f6aab3d8Srobert   if (!l)
755*f6aab3d8Srobert     return {};
756*f6aab3d8Srobert 
757*f6aab3d8Srobert   StringLayout layout = l->GetIndexOfChildWithName(ConstString("__data_")) == 0
758*f6aab3d8Srobert                             ? StringLayout::DSC
759*f6aab3d8Srobert                             : StringLayout::CSD;
760*f6aab3d8Srobert 
761061da546Spatrick   bool short_mode = false; // this means the string is in short-mode and the
762061da546Spatrick                            // data is stored inline
763*f6aab3d8Srobert   bool using_bitmasks = true; // Whether the class uses bitmasks for the mode
764*f6aab3d8Srobert                               // flag (pre-D123580).
765*f6aab3d8Srobert   uint64_t size;
766061da546Spatrick   uint64_t size_mode_value = 0;
767061da546Spatrick 
768*f6aab3d8Srobert   ValueObjectSP short_sp = valobj_rep_sp->GetChildMemberWithName(
769*f6aab3d8Srobert       ConstString("__s"), /*can_create=*/true);
770*f6aab3d8Srobert   if (!short_sp)
771dda28197Spatrick     return {};
772061da546Spatrick 
773*f6aab3d8Srobert   ValueObjectSP is_long =
774*f6aab3d8Srobert       short_sp->GetChildMemberWithName(ConstString("__is_long_"), true);
775*f6aab3d8Srobert   ValueObjectSP size_sp =
776*f6aab3d8Srobert       short_sp->GetChildAtNamePath({ConstString("__size_")});
777*f6aab3d8Srobert   if (!size_sp)
778dda28197Spatrick     return {};
779061da546Spatrick 
780*f6aab3d8Srobert   if (is_long) {
781*f6aab3d8Srobert     using_bitmasks = false;
782*f6aab3d8Srobert     short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0);
783*f6aab3d8Srobert     size = size_sp->GetValueAsUnsigned(/*fail_value=*/0);
784061da546Spatrick   } else {
785*f6aab3d8Srobert     // The string mode is encoded in the size field.
786*f6aab3d8Srobert     size_mode_value = size_sp->GetValueAsUnsigned(0);
787*f6aab3d8Srobert     uint8_t mode_mask = layout == StringLayout::DSC ? 0x80 : 1;
788*f6aab3d8Srobert     short_mode = (size_mode_value & mode_mask) == 0;
789061da546Spatrick   }
790061da546Spatrick 
791061da546Spatrick   if (short_mode) {
792*f6aab3d8Srobert     ValueObjectSP location_sp =
793*f6aab3d8Srobert         short_sp->GetChildMemberWithName(ConstString("__data_"), true);
794*f6aab3d8Srobert     if (using_bitmasks)
795*f6aab3d8Srobert       size = (layout == StringLayout::DSC) ? size_mode_value
796061da546Spatrick                                            : ((size_mode_value >> 1) % 256);
797dda28197Spatrick 
798dda28197Spatrick     // When the small-string optimization takes place, the data must fit in the
799dda28197Spatrick     // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's
800dda28197Spatrick     // likely that the string isn't initialized and we're reading garbage.
801dda28197Spatrick     ExecutionContext exe_ctx(location_sp->GetExecutionContextRef());
802*f6aab3d8Srobert     const std::optional<uint64_t> max_bytes =
803dda28197Spatrick         location_sp->GetCompilerType().GetByteSize(
804dda28197Spatrick             exe_ctx.GetBestExecutionContextScope());
805dda28197Spatrick     if (!max_bytes || size > *max_bytes || !location_sp)
806dda28197Spatrick       return {};
807dda28197Spatrick 
808dda28197Spatrick     return std::make_pair(size, location_sp);
809dda28197Spatrick   }
810dda28197Spatrick 
811061da546Spatrick   // we can use the layout_decider object as the data pointer
812*f6aab3d8Srobert   ValueObjectSP location_sp =
813*f6aab3d8Srobert       l->GetChildMemberWithName(ConstString("__data_"), /*can_create=*/true);
814*f6aab3d8Srobert   ValueObjectSP size_vo =
815*f6aab3d8Srobert       l->GetChildMemberWithName(ConstString("__size_"), /*can_create=*/true);
816*f6aab3d8Srobert   ValueObjectSP capacity_vo =
817*f6aab3d8Srobert       l->GetChildMemberWithName(ConstString("__cap_"), /*can_create=*/true);
818dda28197Spatrick   if (!size_vo || !location_sp || !capacity_vo)
819dda28197Spatrick     return {};
820*f6aab3d8Srobert   size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
821*f6aab3d8Srobert   uint64_t capacity = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
822*f6aab3d8Srobert   if (!using_bitmasks && layout == StringLayout::CSD)
823*f6aab3d8Srobert     capacity *= 2;
824dda28197Spatrick   if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET ||
825dda28197Spatrick       capacity < size)
826dda28197Spatrick     return {};
827dda28197Spatrick   return std::make_pair(size, location_sp);
828061da546Spatrick }
829061da546Spatrick 
830*f6aab3d8Srobert static bool
LibcxxWStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options,ValueObjectSP location_sp,size_t size)831*f6aab3d8Srobert LibcxxWStringSummaryProvider(ValueObject &valobj, Stream &stream,
832*f6aab3d8Srobert                              const TypeSummaryOptions &summary_options,
833*f6aab3d8Srobert                              ValueObjectSP location_sp, size_t size) {
834061da546Spatrick   if (size == 0) {
835061da546Spatrick     stream.Printf("L\"\"");
836061da546Spatrick     return true;
837061da546Spatrick   }
838061da546Spatrick   if (!location_sp)
839061da546Spatrick     return false;
840061da546Spatrick 
841061da546Spatrick   StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
842061da546Spatrick   if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
843061da546Spatrick     const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
844061da546Spatrick     if (size > max_size) {
845061da546Spatrick       size = max_size;
846061da546Spatrick       options.SetIsTruncated(true);
847061da546Spatrick     }
848061da546Spatrick   }
849dda28197Spatrick 
850dda28197Spatrick   DataExtractor extractor;
851dda28197Spatrick   const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
852dda28197Spatrick   if (bytes_read < size)
853dda28197Spatrick     return false;
854061da546Spatrick 
855061da546Spatrick   // std::wstring::size() is measured in 'characters', not bytes
856*f6aab3d8Srobert   TypeSystemClangSP scratch_ts_sp =
857be691f3bSpatrick       ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP());
858*f6aab3d8Srobert   if (!scratch_ts_sp)
859061da546Spatrick     return false;
860061da546Spatrick 
861061da546Spatrick   auto wchar_t_size =
862*f6aab3d8Srobert       scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);
863061da546Spatrick   if (!wchar_t_size)
864061da546Spatrick     return false;
865061da546Spatrick 
866*f6aab3d8Srobert   options.SetData(std::move(extractor));
867061da546Spatrick   options.SetStream(&stream);
868061da546Spatrick   options.SetPrefixToken("L");
869061da546Spatrick   options.SetQuote('"');
870061da546Spatrick   options.SetSourceSize(size);
871061da546Spatrick   options.SetBinaryZeroIsTerminator(false);
872061da546Spatrick 
873061da546Spatrick   switch (*wchar_t_size) {
874061da546Spatrick   case 1:
875dda28197Spatrick     return StringPrinter::ReadBufferAndDumpToStream<
876061da546Spatrick         lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
877061da546Spatrick         options);
878061da546Spatrick     break;
879061da546Spatrick 
880061da546Spatrick   case 2:
881dda28197Spatrick     return StringPrinter::ReadBufferAndDumpToStream<
882061da546Spatrick         lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
883061da546Spatrick         options);
884061da546Spatrick     break;
885061da546Spatrick 
886061da546Spatrick   case 4:
887dda28197Spatrick     return StringPrinter::ReadBufferAndDumpToStream<
888061da546Spatrick         lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
889061da546Spatrick         options);
890061da546Spatrick   }
891dda28197Spatrick   return false;
892061da546Spatrick }
893061da546Spatrick 
LibcxxWStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options)894*f6aab3d8Srobert bool lldb_private::formatters::LibcxxWStringSummaryProvider(
895*f6aab3d8Srobert     ValueObject &valobj, Stream &stream,
896*f6aab3d8Srobert     const TypeSummaryOptions &summary_options) {
897dda28197Spatrick   auto string_info = ExtractLibcxxStringInfo(valobj);
898dda28197Spatrick   if (!string_info)
899061da546Spatrick     return false;
900dda28197Spatrick   uint64_t size;
901dda28197Spatrick   ValueObjectSP location_sp;
902dda28197Spatrick   std::tie(size, location_sp) = *string_info;
903061da546Spatrick 
904*f6aab3d8Srobert   return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
905*f6aab3d8Srobert                                         location_sp, size);
906*f6aab3d8Srobert }
907*f6aab3d8Srobert 
908*f6aab3d8Srobert template <StringPrinter::StringElementType element_type>
909*f6aab3d8Srobert static bool
LibcxxStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options,std::string prefix_token,ValueObjectSP location_sp,uint64_t size)910*f6aab3d8Srobert LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
911*f6aab3d8Srobert                             const TypeSummaryOptions &summary_options,
912*f6aab3d8Srobert                             std::string prefix_token, ValueObjectSP location_sp,
913*f6aab3d8Srobert                             uint64_t size) {
914*f6aab3d8Srobert 
915061da546Spatrick   if (size == 0) {
916061da546Spatrick     stream.Printf("\"\"");
917061da546Spatrick     return true;
918061da546Spatrick   }
919061da546Spatrick 
920061da546Spatrick   if (!location_sp)
921061da546Spatrick     return false;
922061da546Spatrick 
923061da546Spatrick   StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
924061da546Spatrick 
925061da546Spatrick   if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
926061da546Spatrick     const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
927061da546Spatrick     if (size > max_size) {
928061da546Spatrick       size = max_size;
929061da546Spatrick       options.SetIsTruncated(true);
930061da546Spatrick     }
931061da546Spatrick   }
932dda28197Spatrick 
933*f6aab3d8Srobert   {
934dda28197Spatrick     DataExtractor extractor;
935dda28197Spatrick     const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
936dda28197Spatrick     if (bytes_read < size)
937dda28197Spatrick       return false;
938061da546Spatrick 
939*f6aab3d8Srobert     options.SetData(std::move(extractor));
940*f6aab3d8Srobert   }
941061da546Spatrick   options.SetStream(&stream);
942061da546Spatrick   if (prefix_token.empty())
943061da546Spatrick     options.SetPrefixToken(nullptr);
944061da546Spatrick   else
945061da546Spatrick     options.SetPrefixToken(prefix_token);
946061da546Spatrick   options.SetQuote('"');
947061da546Spatrick   options.SetSourceSize(size);
948061da546Spatrick   options.SetBinaryZeroIsTerminator(false);
949dda28197Spatrick   return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
950dda28197Spatrick }
951061da546Spatrick 
952dda28197Spatrick template <StringPrinter::StringElementType element_type>
953*f6aab3d8Srobert static bool
LibcxxStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options,std::string prefix_token)954*f6aab3d8Srobert LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
955*f6aab3d8Srobert                             const TypeSummaryOptions &summary_options,
956*f6aab3d8Srobert                             std::string prefix_token) {
957*f6aab3d8Srobert   auto string_info = ExtractLibcxxStringInfo(valobj);
958*f6aab3d8Srobert   if (!string_info)
959*f6aab3d8Srobert     return false;
960*f6aab3d8Srobert   uint64_t size;
961*f6aab3d8Srobert   ValueObjectSP location_sp;
962*f6aab3d8Srobert   std::tie(size, location_sp) = *string_info;
963*f6aab3d8Srobert 
964*f6aab3d8Srobert   return LibcxxStringSummaryProvider<element_type>(
965*f6aab3d8Srobert       valobj, stream, summary_options, prefix_token, location_sp, size);
966*f6aab3d8Srobert }
967*f6aab3d8Srobert template <StringPrinter::StringElementType element_type>
formatStringImpl(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options,std::string prefix_token)968dda28197Spatrick static bool formatStringImpl(ValueObject &valobj, Stream &stream,
969dda28197Spatrick                              const TypeSummaryOptions &summary_options,
970dda28197Spatrick                              std::string prefix_token) {
971dda28197Spatrick   StreamString scratch_stream;
972dda28197Spatrick   const bool success = LibcxxStringSummaryProvider<element_type>(
973dda28197Spatrick       valobj, scratch_stream, summary_options, prefix_token);
974dda28197Spatrick   if (success)
975dda28197Spatrick     stream << scratch_stream.GetData();
976dda28197Spatrick   else
977dda28197Spatrick     stream << "Summary Unavailable";
978061da546Spatrick   return true;
979061da546Spatrick }
980061da546Spatrick 
LibcxxStringSummaryProviderASCII(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options)981061da546Spatrick bool lldb_private::formatters::LibcxxStringSummaryProviderASCII(
982061da546Spatrick     ValueObject &valobj, Stream &stream,
983061da546Spatrick     const TypeSummaryOptions &summary_options) {
984dda28197Spatrick   return formatStringImpl<StringPrinter::StringElementType::ASCII>(
985dda28197Spatrick       valobj, stream, summary_options, "");
986061da546Spatrick }
987061da546Spatrick 
LibcxxStringSummaryProviderUTF16(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options)988061da546Spatrick bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16(
989061da546Spatrick     ValueObject &valobj, Stream &stream,
990061da546Spatrick     const TypeSummaryOptions &summary_options) {
991dda28197Spatrick   return formatStringImpl<StringPrinter::StringElementType::UTF16>(
992061da546Spatrick       valobj, stream, summary_options, "u");
993061da546Spatrick }
994061da546Spatrick 
LibcxxStringSummaryProviderUTF32(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options)995061da546Spatrick bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32(
996061da546Spatrick     ValueObject &valobj, Stream &stream,
997061da546Spatrick     const TypeSummaryOptions &summary_options) {
998dda28197Spatrick   return formatStringImpl<StringPrinter::StringElementType::UTF32>(
999061da546Spatrick       valobj, stream, summary_options, "U");
1000061da546Spatrick }
1001*f6aab3d8Srobert 
1002*f6aab3d8Srobert static std::tuple<bool, ValueObjectSP, size_t>
LibcxxExtractStringViewData(ValueObject & valobj)1003*f6aab3d8Srobert LibcxxExtractStringViewData(ValueObject& valobj) {
1004*f6aab3d8Srobert   auto dataobj = GetChildMemberWithName(
1005*f6aab3d8Srobert       valobj, {ConstString("__data_"), ConstString("__data")});
1006*f6aab3d8Srobert   auto sizeobj = GetChildMemberWithName(
1007*f6aab3d8Srobert       valobj, {ConstString("__size_"), ConstString("__size")});
1008*f6aab3d8Srobert   if (!dataobj || !sizeobj)
1009*f6aab3d8Srobert     return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
1010*f6aab3d8Srobert 
1011*f6aab3d8Srobert   if (!dataobj->GetError().Success() || !sizeobj->GetError().Success())
1012*f6aab3d8Srobert     return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
1013*f6aab3d8Srobert 
1014*f6aab3d8Srobert   bool success{false};
1015*f6aab3d8Srobert   uint64_t size = sizeobj->GetValueAsUnsigned(0, &success);
1016*f6aab3d8Srobert   if (!success)
1017*f6aab3d8Srobert     return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
1018*f6aab3d8Srobert 
1019*f6aab3d8Srobert   return std::make_tuple(true,dataobj,size);
1020*f6aab3d8Srobert }
1021*f6aab3d8Srobert 
1022*f6aab3d8Srobert template <StringPrinter::StringElementType element_type>
formatStringViewImpl(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options,std::string prefix_token)1023*f6aab3d8Srobert static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,
1024*f6aab3d8Srobert                                  const TypeSummaryOptions &summary_options,
1025*f6aab3d8Srobert                                  std::string prefix_token) {
1026*f6aab3d8Srobert 
1027*f6aab3d8Srobert   bool success;
1028*f6aab3d8Srobert   ValueObjectSP dataobj;
1029*f6aab3d8Srobert   size_t size;
1030*f6aab3d8Srobert   std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);
1031*f6aab3d8Srobert 
1032*f6aab3d8Srobert   if (!success) {
1033*f6aab3d8Srobert     stream << "Summary Unavailable";
1034*f6aab3d8Srobert     return true;
1035*f6aab3d8Srobert   }
1036*f6aab3d8Srobert 
1037*f6aab3d8Srobert   return LibcxxStringSummaryProvider<element_type>(
1038*f6aab3d8Srobert       valobj, stream, summary_options, prefix_token, dataobj, size);
1039*f6aab3d8Srobert }
1040*f6aab3d8Srobert 
LibcxxStringViewSummaryProviderASCII(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options)1041*f6aab3d8Srobert bool lldb_private::formatters::LibcxxStringViewSummaryProviderASCII(
1042*f6aab3d8Srobert     ValueObject &valobj, Stream &stream,
1043*f6aab3d8Srobert     const TypeSummaryOptions &summary_options) {
1044*f6aab3d8Srobert   return formatStringViewImpl<StringPrinter::StringElementType::ASCII>(
1045*f6aab3d8Srobert       valobj, stream, summary_options, "");
1046*f6aab3d8Srobert }
1047*f6aab3d8Srobert 
LibcxxStringViewSummaryProviderUTF16(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options)1048*f6aab3d8Srobert bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16(
1049*f6aab3d8Srobert     ValueObject &valobj, Stream &stream,
1050*f6aab3d8Srobert     const TypeSummaryOptions &summary_options) {
1051*f6aab3d8Srobert   return formatStringViewImpl<StringPrinter::StringElementType::UTF16>(
1052*f6aab3d8Srobert       valobj, stream, summary_options, "u");
1053*f6aab3d8Srobert }
1054*f6aab3d8Srobert 
LibcxxStringViewSummaryProviderUTF32(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options)1055*f6aab3d8Srobert bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32(
1056*f6aab3d8Srobert     ValueObject &valobj, Stream &stream,
1057*f6aab3d8Srobert     const TypeSummaryOptions &summary_options) {
1058*f6aab3d8Srobert   return formatStringViewImpl<StringPrinter::StringElementType::UTF32>(
1059*f6aab3d8Srobert       valobj, stream, summary_options, "U");
1060*f6aab3d8Srobert }
1061*f6aab3d8Srobert 
LibcxxWStringViewSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options)1062*f6aab3d8Srobert bool lldb_private::formatters::LibcxxWStringViewSummaryProvider(
1063*f6aab3d8Srobert     ValueObject &valobj, Stream &stream,
1064*f6aab3d8Srobert     const TypeSummaryOptions &summary_options) {
1065*f6aab3d8Srobert 
1066*f6aab3d8Srobert   bool success;
1067*f6aab3d8Srobert   ValueObjectSP dataobj;
1068*f6aab3d8Srobert   size_t size;
1069*f6aab3d8Srobert   std::tie( success, dataobj, size ) = LibcxxExtractStringViewData(valobj);
1070*f6aab3d8Srobert 
1071*f6aab3d8Srobert   if (!success) {
1072*f6aab3d8Srobert     stream << "Summary Unavailable";
1073*f6aab3d8Srobert     return true;
1074*f6aab3d8Srobert   }
1075*f6aab3d8Srobert 
1076*f6aab3d8Srobert 
1077*f6aab3d8Srobert   return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
1078*f6aab3d8Srobert                                         dataobj, size);
1079*f6aab3d8Srobert }
1080