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