Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
39644 views
1
//===-- LibCxx.cpp --------------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "LibCxx.h"
10
11
#include "lldb/Core/Debugger.h"
12
#include "lldb/Core/FormatEntity.h"
13
#include "lldb/Core/ValueObject.h"
14
#include "lldb/Core/ValueObjectConstResult.h"
15
#include "lldb/DataFormatters/FormattersHelpers.h"
16
#include "lldb/DataFormatters/StringPrinter.h"
17
#include "lldb/DataFormatters/TypeSummary.h"
18
#include "lldb/DataFormatters/VectorIterator.h"
19
#include "lldb/Target/SectionLoadList.h"
20
#include "lldb/Target/Target.h"
21
#include "lldb/Utility/ConstString.h"
22
#include "lldb/Utility/DataBufferHeap.h"
23
#include "lldb/Utility/Endian.h"
24
#include "lldb/Utility/Status.h"
25
#include "lldb/Utility/Stream.h"
26
27
#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
28
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
29
#include "lldb/lldb-enumerations.h"
30
#include <optional>
31
#include <tuple>
32
33
using namespace lldb;
34
using namespace lldb_private;
35
using namespace lldb_private::formatters;
36
37
lldb::ValueObjectSP lldb_private::formatters::GetChildMemberWithName(
38
ValueObject &obj, llvm::ArrayRef<ConstString> alternative_names) {
39
for (ConstString name : alternative_names) {
40
lldb::ValueObjectSP child_sp = obj.GetChildMemberWithName(name);
41
42
if (child_sp)
43
return child_sp;
44
}
45
return {};
46
}
47
48
lldb::ValueObjectSP
49
lldb_private::formatters::GetFirstValueOfLibCXXCompressedPair(
50
ValueObject &pair) {
51
ValueObjectSP value;
52
ValueObjectSP first_child = pair.GetChildAtIndex(0);
53
if (first_child)
54
value = first_child->GetChildMemberWithName("__value_");
55
if (!value) {
56
// pre-r300140 member name
57
value = pair.GetChildMemberWithName("__first_");
58
}
59
return value;
60
}
61
62
lldb::ValueObjectSP
63
lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(
64
ValueObject &pair) {
65
ValueObjectSP value;
66
if (pair.GetNumChildrenIgnoringErrors() > 1) {
67
ValueObjectSP second_child = pair.GetChildAtIndex(1);
68
if (second_child) {
69
value = second_child->GetChildMemberWithName("__value_");
70
}
71
}
72
if (!value) {
73
// pre-r300140 member name
74
value = pair.GetChildMemberWithName("__second_");
75
}
76
return value;
77
}
78
79
bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
80
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
81
82
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
83
84
if (!valobj_sp)
85
return false;
86
87
ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
88
Process *process = exe_ctx.GetProcessPtr();
89
90
if (process == nullptr)
91
return false;
92
93
CPPLanguageRuntime *cpp_runtime = CPPLanguageRuntime::Get(*process);
94
95
if (!cpp_runtime)
96
return false;
97
98
CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =
99
cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp);
100
101
switch (callable_info.callable_case) {
102
case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid:
103
stream.Printf(" __f_ = %" PRIu64, callable_info.member_f_pointer_value);
104
return false;
105
break;
106
case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda:
107
stream.Printf(
108
" Lambda in File %s at Line %u",
109
callable_info.callable_line_entry.GetFile().GetFilename().GetCString(),
110
callable_info.callable_line_entry.line);
111
break;
112
case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject:
113
stream.Printf(
114
" Function in File %s at Line %u",
115
callable_info.callable_line_entry.GetFile().GetFilename().GetCString(),
116
callable_info.callable_line_entry.line);
117
break;
118
case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction:
119
stream.Printf(" Function = %s ",
120
callable_info.callable_symbol.GetName().GetCString());
121
break;
122
}
123
124
return true;
125
}
126
127
bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
128
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
129
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
130
if (!valobj_sp)
131
return false;
132
ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
133
ValueObjectSP count_sp(
134
valobj_sp->GetChildAtNamePath({"__cntrl_", "__shared_owners_"}));
135
ValueObjectSP weakcount_sp(
136
valobj_sp->GetChildAtNamePath({"__cntrl_", "__shared_weak_owners_"}));
137
138
if (!ptr_sp)
139
return false;
140
141
if (ptr_sp->GetValueAsUnsigned(0) == 0) {
142
stream.Printf("nullptr");
143
return true;
144
} else {
145
bool print_pointee = false;
146
Status error;
147
ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
148
if (pointee_sp && error.Success()) {
149
if (pointee_sp->DumpPrintableRepresentation(
150
stream, ValueObject::eValueObjectRepresentationStyleSummary,
151
lldb::eFormatInvalid,
152
ValueObject::PrintableRepresentationSpecialCases::eDisable,
153
false))
154
print_pointee = true;
155
}
156
if (!print_pointee)
157
stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
158
}
159
160
if (count_sp)
161
stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0));
162
163
if (weakcount_sp)
164
stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0));
165
166
return true;
167
}
168
169
bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
170
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
171
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
172
if (!valobj_sp)
173
return false;
174
175
ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
176
if (!ptr_sp)
177
return false;
178
179
ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
180
if (!ptr_sp)
181
return false;
182
183
if (ptr_sp->GetValueAsUnsigned(0) == 0) {
184
stream.Printf("nullptr");
185
return true;
186
} else {
187
bool print_pointee = false;
188
Status error;
189
ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
190
if (pointee_sp && error.Success()) {
191
if (pointee_sp->DumpPrintableRepresentation(
192
stream, ValueObject::eValueObjectRepresentationStyleSummary,
193
lldb::eFormatInvalid,
194
ValueObject::PrintableRepresentationSpecialCases::eDisable,
195
false))
196
print_pointee = true;
197
}
198
if (!print_pointee)
199
stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
200
}
201
202
return true;
203
}
204
205
/*
206
(lldb) fr var ibeg --raw --ptr-depth 1 -T
207
(std::__1::__wrap_iter<int *>) ibeg = {
208
(std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
209
(int) *__i = 1
210
}
211
}
212
*/
213
214
SyntheticChildrenFrontEnd *
215
lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(
216
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
217
return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
218
valobj_sp, {ConstString("__i_"), ConstString("__i")})
219
: nullptr);
220
}
221
222
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
223
LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
224
: SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr) {
225
if (valobj_sp)
226
Update();
227
}
228
229
llvm::Expected<uint32_t> lldb_private::formatters::
230
LibcxxSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
231
return (m_cntrl ? 1 : 0);
232
}
233
234
lldb::ValueObjectSP
235
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(
236
uint32_t idx) {
237
if (!m_cntrl)
238
return lldb::ValueObjectSP();
239
240
ValueObjectSP valobj_sp = m_backend.GetSP();
241
if (!valobj_sp)
242
return lldb::ValueObjectSP();
243
244
if (idx == 0)
245
return valobj_sp->GetChildMemberWithName("__ptr_");
246
247
if (idx == 1) {
248
if (auto ptr_sp = valobj_sp->GetChildMemberWithName("__ptr_")) {
249
Status status;
250
auto value_type_sp =
251
valobj_sp->GetCompilerType()
252
.GetTypeTemplateArgument(0).GetPointerType();
253
ValueObjectSP cast_ptr_sp = ptr_sp->Cast(value_type_sp);
254
ValueObjectSP value_sp = cast_ptr_sp->Dereference(status);
255
if (status.Success()) {
256
return value_sp;
257
}
258
}
259
}
260
261
return lldb::ValueObjectSP();
262
}
263
264
lldb::ChildCacheState
265
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {
266
m_cntrl = nullptr;
267
268
ValueObjectSP valobj_sp = m_backend.GetSP();
269
if (!valobj_sp)
270
return lldb::ChildCacheState::eRefetch;
271
272
TargetSP target_sp(valobj_sp->GetTargetSP());
273
if (!target_sp)
274
return lldb::ChildCacheState::eRefetch;
275
276
lldb::ValueObjectSP cntrl_sp(valobj_sp->GetChildMemberWithName("__cntrl_"));
277
278
m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular
279
// dependency
280
return lldb::ChildCacheState::eRefetch;
281
}
282
283
bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
284
MightHaveChildren() {
285
return true;
286
}
287
288
size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
289
GetIndexOfChildWithName(ConstString name) {
290
if (name == "__ptr_")
291
return 0;
292
if (name == "$$dereference$$")
293
return 1;
294
return UINT32_MAX;
295
}
296
297
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
298
~LibcxxSharedPtrSyntheticFrontEnd() = default;
299
300
SyntheticChildrenFrontEnd *
301
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(
302
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
303
return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)
304
: nullptr);
305
}
306
307
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
308
LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
309
: SyntheticChildrenFrontEnd(*valobj_sp) {
310
if (valobj_sp)
311
Update();
312
}
313
314
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
315
~LibcxxUniquePtrSyntheticFrontEnd() = default;
316
317
SyntheticChildrenFrontEnd *
318
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator(
319
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
320
return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp)
321
: nullptr);
322
}
323
324
llvm::Expected<uint32_t> lldb_private::formatters::
325
LibcxxUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
326
if (m_value_ptr_sp)
327
return m_deleter_sp ? 2 : 1;
328
return 0;
329
}
330
331
lldb::ValueObjectSP
332
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex(
333
uint32_t idx) {
334
if (!m_value_ptr_sp)
335
return lldb::ValueObjectSP();
336
337
if (idx == 0)
338
return m_value_ptr_sp;
339
340
if (idx == 1)
341
return m_deleter_sp;
342
343
if (idx == 2) {
344
Status status;
345
auto value_sp = m_value_ptr_sp->Dereference(status);
346
if (status.Success()) {
347
return value_sp;
348
}
349
}
350
351
return lldb::ValueObjectSP();
352
}
353
354
lldb::ChildCacheState
355
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
356
ValueObjectSP valobj_sp = m_backend.GetSP();
357
if (!valobj_sp)
358
return lldb::ChildCacheState::eRefetch;
359
360
ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
361
if (!ptr_sp)
362
return lldb::ChildCacheState::eRefetch;
363
364
// Retrieve the actual pointer and the deleter, and clone them to give them
365
// user-friendly names.
366
ValueObjectSP value_pointer_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
367
if (value_pointer_sp)
368
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
369
370
ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);
371
if (deleter_sp)
372
m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
373
374
return lldb::ChildCacheState::eRefetch;
375
}
376
377
bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
378
MightHaveChildren() {
379
return true;
380
}
381
382
size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
383
GetIndexOfChildWithName(ConstString name) {
384
if (name == "pointer")
385
return 0;
386
if (name == "deleter")
387
return 1;
388
if (name == "$$dereference$$")
389
return 2;
390
return UINT32_MAX;
391
}
392
393
bool lldb_private::formatters::LibcxxContainerSummaryProvider(
394
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
395
if (valobj.IsPointerType()) {
396
uint64_t value = valobj.GetValueAsUnsigned(0);
397
if (!value)
398
return false;
399
stream.Printf("0x%016" PRIx64 " ", value);
400
}
401
return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr,
402
nullptr, nullptr, &valobj, false, false);
403
}
404
405
/// The field layout in a libc++ string (cap, side, data or data, size, cap).
406
namespace {
407
enum class StringLayout { CSD, DSC };
408
}
409
410
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
411
/// extract its data payload. Return the size + payload pair.
412
// TODO: Support big-endian architectures.
413
static std::optional<std::pair<uint64_t, ValueObjectSP>>
414
ExtractLibcxxStringInfo(ValueObject &valobj) {
415
ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
416
if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
417
return {};
418
419
// __r_ is a compressed_pair of the actual data and the allocator. The data we
420
// want is in the first base class.
421
ValueObjectSP valobj_r_base_sp = valobj_r_sp->GetChildAtIndex(0);
422
if (!valobj_r_base_sp)
423
return {};
424
425
ValueObjectSP valobj_rep_sp =
426
valobj_r_base_sp->GetChildMemberWithName("__value_");
427
if (!valobj_rep_sp)
428
return {};
429
430
ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName("__l");
431
if (!l)
432
return {};
433
434
StringLayout layout = l->GetIndexOfChildWithName("__data_") == 0
435
? StringLayout::DSC
436
: StringLayout::CSD;
437
438
bool short_mode = false; // this means the string is in short-mode and the
439
// data is stored inline
440
bool using_bitmasks = true; // Whether the class uses bitmasks for the mode
441
// flag (pre-D123580).
442
uint64_t size;
443
uint64_t size_mode_value = 0;
444
445
ValueObjectSP short_sp = valobj_rep_sp->GetChildMemberWithName("__s");
446
if (!short_sp)
447
return {};
448
449
ValueObjectSP is_long = short_sp->GetChildMemberWithName("__is_long_");
450
ValueObjectSP size_sp = short_sp->GetChildMemberWithName("__size_");
451
if (!size_sp)
452
return {};
453
454
if (is_long) {
455
using_bitmasks = false;
456
short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0);
457
size = size_sp->GetValueAsUnsigned(/*fail_value=*/0);
458
} else {
459
// The string mode is encoded in the size field.
460
size_mode_value = size_sp->GetValueAsUnsigned(0);
461
uint8_t mode_mask = layout == StringLayout::DSC ? 0x80 : 1;
462
short_mode = (size_mode_value & mode_mask) == 0;
463
}
464
465
if (short_mode) {
466
ValueObjectSP location_sp = short_sp->GetChildMemberWithName("__data_");
467
if (using_bitmasks)
468
size = (layout == StringLayout::DSC) ? size_mode_value
469
: ((size_mode_value >> 1) % 256);
470
471
if (!location_sp)
472
return {};
473
474
// When the small-string optimization takes place, the data must fit in the
475
// inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's
476
// likely that the string isn't initialized and we're reading garbage.
477
ExecutionContext exe_ctx(location_sp->GetExecutionContextRef());
478
const std::optional<uint64_t> max_bytes =
479
location_sp->GetCompilerType().GetByteSize(
480
exe_ctx.GetBestExecutionContextScope());
481
if (!max_bytes || size > *max_bytes)
482
return {};
483
484
return std::make_pair(size, location_sp);
485
}
486
487
// we can use the layout_decider object as the data pointer
488
ValueObjectSP location_sp = l->GetChildMemberWithName("__data_");
489
ValueObjectSP size_vo = l->GetChildMemberWithName("__size_");
490
ValueObjectSP capacity_vo = l->GetChildMemberWithName("__cap_");
491
if (!size_vo || !location_sp || !capacity_vo)
492
return {};
493
size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
494
uint64_t capacity = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
495
if (!using_bitmasks && layout == StringLayout::CSD)
496
capacity *= 2;
497
if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET ||
498
capacity < size)
499
return {};
500
return std::make_pair(size, location_sp);
501
}
502
503
static bool
504
LibcxxWStringSummaryProvider(ValueObject &valobj, Stream &stream,
505
const TypeSummaryOptions &summary_options,
506
ValueObjectSP location_sp, size_t size) {
507
if (size == 0) {
508
stream.Printf("L\"\"");
509
return true;
510
}
511
if (!location_sp)
512
return false;
513
514
StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
515
if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
516
const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
517
if (size > max_size) {
518
size = max_size;
519
options.SetIsTruncated(true);
520
}
521
}
522
523
DataExtractor extractor;
524
const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
525
if (bytes_read < size)
526
return false;
527
528
// std::wstring::size() is measured in 'characters', not bytes
529
TypeSystemClangSP scratch_ts_sp =
530
ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP());
531
if (!scratch_ts_sp)
532
return false;
533
534
auto wchar_t_size =
535
scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);
536
if (!wchar_t_size)
537
return false;
538
539
options.SetData(std::move(extractor));
540
options.SetStream(&stream);
541
options.SetPrefixToken("L");
542
options.SetQuote('"');
543
options.SetSourceSize(size);
544
options.SetBinaryZeroIsTerminator(false);
545
546
switch (*wchar_t_size) {
547
case 1:
548
return StringPrinter::ReadBufferAndDumpToStream<
549
lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
550
options);
551
break;
552
553
case 2:
554
return StringPrinter::ReadBufferAndDumpToStream<
555
lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
556
options);
557
break;
558
559
case 4:
560
return StringPrinter::ReadBufferAndDumpToStream<
561
lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
562
options);
563
}
564
return false;
565
}
566
567
bool lldb_private::formatters::LibcxxWStringSummaryProvider(
568
ValueObject &valobj, Stream &stream,
569
const TypeSummaryOptions &summary_options) {
570
auto string_info = ExtractLibcxxStringInfo(valobj);
571
if (!string_info)
572
return false;
573
uint64_t size;
574
ValueObjectSP location_sp;
575
std::tie(size, location_sp) = *string_info;
576
577
return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
578
location_sp, size);
579
}
580
581
template <StringPrinter::StringElementType element_type>
582
static bool
583
LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
584
const TypeSummaryOptions &summary_options,
585
std::string prefix_token, ValueObjectSP location_sp,
586
uint64_t size) {
587
588
if (size == 0) {
589
stream.Printf("\"\"");
590
return true;
591
}
592
593
if (!location_sp)
594
return false;
595
596
StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
597
598
if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
599
const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
600
if (size > max_size) {
601
size = max_size;
602
options.SetIsTruncated(true);
603
}
604
}
605
606
{
607
DataExtractor extractor;
608
const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
609
if (bytes_read < size)
610
return false;
611
612
options.SetData(std::move(extractor));
613
}
614
options.SetStream(&stream);
615
if (prefix_token.empty())
616
options.SetPrefixToken(nullptr);
617
else
618
options.SetPrefixToken(prefix_token);
619
options.SetQuote('"');
620
options.SetSourceSize(size);
621
options.SetBinaryZeroIsTerminator(false);
622
return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
623
}
624
625
template <StringPrinter::StringElementType element_type>
626
static bool
627
LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
628
const TypeSummaryOptions &summary_options,
629
std::string prefix_token) {
630
auto string_info = ExtractLibcxxStringInfo(valobj);
631
if (!string_info)
632
return false;
633
uint64_t size;
634
ValueObjectSP location_sp;
635
std::tie(size, location_sp) = *string_info;
636
637
return LibcxxStringSummaryProvider<element_type>(
638
valobj, stream, summary_options, prefix_token, location_sp, size);
639
}
640
template <StringPrinter::StringElementType element_type>
641
static bool formatStringImpl(ValueObject &valobj, Stream &stream,
642
const TypeSummaryOptions &summary_options,
643
std::string prefix_token) {
644
StreamString scratch_stream;
645
const bool success = LibcxxStringSummaryProvider<element_type>(
646
valobj, scratch_stream, summary_options, prefix_token);
647
if (success)
648
stream << scratch_stream.GetData();
649
else
650
stream << "Summary Unavailable";
651
return true;
652
}
653
654
bool lldb_private::formatters::LibcxxStringSummaryProviderASCII(
655
ValueObject &valobj, Stream &stream,
656
const TypeSummaryOptions &summary_options) {
657
return formatStringImpl<StringPrinter::StringElementType::ASCII>(
658
valobj, stream, summary_options, "");
659
}
660
661
bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16(
662
ValueObject &valobj, Stream &stream,
663
const TypeSummaryOptions &summary_options) {
664
return formatStringImpl<StringPrinter::StringElementType::UTF16>(
665
valobj, stream, summary_options, "u");
666
}
667
668
bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32(
669
ValueObject &valobj, Stream &stream,
670
const TypeSummaryOptions &summary_options) {
671
return formatStringImpl<StringPrinter::StringElementType::UTF32>(
672
valobj, stream, summary_options, "U");
673
}
674
675
static std::tuple<bool, ValueObjectSP, size_t>
676
LibcxxExtractStringViewData(ValueObject& valobj) {
677
auto dataobj = GetChildMemberWithName(
678
valobj, {ConstString("__data_"), ConstString("__data")});
679
auto sizeobj = GetChildMemberWithName(
680
valobj, {ConstString("__size_"), ConstString("__size")});
681
if (!dataobj || !sizeobj)
682
return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
683
684
if (!dataobj->GetError().Success() || !sizeobj->GetError().Success())
685
return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
686
687
bool success{false};
688
uint64_t size = sizeobj->GetValueAsUnsigned(0, &success);
689
if (!success)
690
return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
691
692
return std::make_tuple(true,dataobj,size);
693
}
694
695
template <StringPrinter::StringElementType element_type>
696
static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,
697
const TypeSummaryOptions &summary_options,
698
std::string prefix_token) {
699
700
bool success;
701
ValueObjectSP dataobj;
702
size_t size;
703
std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);
704
705
if (!success) {
706
stream << "Summary Unavailable";
707
return true;
708
}
709
710
return LibcxxStringSummaryProvider<element_type>(
711
valobj, stream, summary_options, prefix_token, dataobj, size);
712
}
713
714
bool lldb_private::formatters::LibcxxStringViewSummaryProviderASCII(
715
ValueObject &valobj, Stream &stream,
716
const TypeSummaryOptions &summary_options) {
717
return formatStringViewImpl<StringPrinter::StringElementType::ASCII>(
718
valobj, stream, summary_options, "");
719
}
720
721
bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16(
722
ValueObject &valobj, Stream &stream,
723
const TypeSummaryOptions &summary_options) {
724
return formatStringViewImpl<StringPrinter::StringElementType::UTF16>(
725
valobj, stream, summary_options, "u");
726
}
727
728
bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32(
729
ValueObject &valobj, Stream &stream,
730
const TypeSummaryOptions &summary_options) {
731
return formatStringViewImpl<StringPrinter::StringElementType::UTF32>(
732
valobj, stream, summary_options, "U");
733
}
734
735
bool lldb_private::formatters::LibcxxWStringViewSummaryProvider(
736
ValueObject &valobj, Stream &stream,
737
const TypeSummaryOptions &summary_options) {
738
739
bool success;
740
ValueObjectSP dataobj;
741
size_t size;
742
std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);
743
744
if (!success) {
745
stream << "Summary Unavailable";
746
return true;
747
}
748
749
return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
750
dataobj, size);
751
}
752
753
static bool
754
LibcxxChronoTimePointSecondsSummaryProvider(ValueObject &valobj, Stream &stream,
755
const TypeSummaryOptions &options,
756
const char *fmt) {
757
ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");
758
if (!ptr_sp)
759
return false;
760
ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");
761
if (!ptr_sp)
762
return false;
763
764
#ifndef _WIN32
765
// The date time in the chrono library is valid in the range
766
// [-32767-01-01T00:00:00Z, 32767-12-31T23:59:59Z]. A 64-bit time_t has a
767
// larger range, the function strftime is not able to format the entire range
768
// of time_t. The exact point has not been investigated; it's limited to
769
// chrono's range.
770
const std::time_t chrono_timestamp_min =
771
-1'096'193'779'200; // -32767-01-01T00:00:00Z
772
const std::time_t chrono_timestamp_max =
773
971'890'963'199; // 32767-12-31T23:59:59Z
774
#else
775
const std::time_t chrono_timestamp_min = -43'200; // 1969-12-31T12:00:00Z
776
const std::time_t chrono_timestamp_max =
777
32'536'850'399; // 3001-01-19T21:59:59
778
#endif
779
780
const std::time_t seconds = ptr_sp->GetValueAsSigned(0);
781
if (seconds < chrono_timestamp_min || seconds > chrono_timestamp_max)
782
stream.Printf("timestamp=%" PRId64 " s", static_cast<int64_t>(seconds));
783
else {
784
std::array<char, 128> str;
785
std::size_t size =
786
std::strftime(str.data(), str.size(), fmt, gmtime(&seconds));
787
if (size == 0)
788
return false;
789
790
stream.Printf("date/time=%s timestamp=%" PRId64 " s", str.data(),
791
static_cast<int64_t>(seconds));
792
}
793
794
return true;
795
}
796
797
bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider(
798
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
799
return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options,
800
"%FT%H:%M:%SZ");
801
}
802
803
bool lldb_private::formatters::LibcxxChronoLocalSecondsSummaryProvider(
804
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
805
return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options,
806
"%FT%H:%M:%S");
807
}
808
809
static bool
810
LibcxxChronoTimepointDaysSummaryProvider(ValueObject &valobj, Stream &stream,
811
const TypeSummaryOptions &options,
812
const char *fmt) {
813
ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");
814
if (!ptr_sp)
815
return false;
816
ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");
817
if (!ptr_sp)
818
return false;
819
820
#ifndef _WIN32
821
// The date time in the chrono library is valid in the range
822
// [-32767-01-01Z, 32767-12-31Z]. A 32-bit time_t has a larger range, the
823
// function strftime is not able to format the entire range of time_t. The
824
// exact point has not been investigated; it's limited to chrono's range.
825
const int chrono_timestamp_min = -12'687'428; // -32767-01-01Z
826
const int chrono_timestamp_max = 11'248'737; // 32767-12-31Z
827
#else
828
const int chrono_timestamp_min = 0; // 1970-01-01Z
829
const int chrono_timestamp_max = 376'583; // 3001-01-19Z
830
#endif
831
832
const int days = ptr_sp->GetValueAsSigned(0);
833
if (days < chrono_timestamp_min || days > chrono_timestamp_max)
834
stream.Printf("timestamp=%d days", days);
835
836
else {
837
const std::time_t seconds = std::time_t(86400) * days;
838
839
std::array<char, 128> str;
840
std::size_t size =
841
std::strftime(str.data(), str.size(), fmt, gmtime(&seconds));
842
if (size == 0)
843
return false;
844
845
stream.Printf("date=%s timestamp=%d days", str.data(), days);
846
}
847
848
return true;
849
}
850
851
bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider(
852
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
853
return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options,
854
"%FZ");
855
}
856
857
bool lldb_private::formatters::LibcxxChronoLocalDaysSummaryProvider(
858
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
859
return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options,
860
"%F");
861
}
862
863
bool lldb_private::formatters::LibcxxChronoMonthSummaryProvider(
864
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
865
// FIXME: These are the names used in the C++20 ostream operator. Since LLVM
866
// uses C++17 it's not possible to use the ostream operator directly.
867
static const std::array<std::string_view, 12> months = {
868
"January", "February", "March", "April", "May", "June",
869
"July", "August", "September", "October", "November", "December"};
870
871
ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__m_");
872
if (!ptr_sp)
873
return false;
874
875
const unsigned month = ptr_sp->GetValueAsUnsigned(0);
876
if (month >= 1 && month <= 12)
877
stream << "month=" << months[month - 1];
878
else
879
stream.Printf("month=%u", month);
880
881
return true;
882
}
883
884
bool lldb_private::formatters::LibcxxChronoWeekdaySummaryProvider(
885
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
886
// FIXME: These are the names used in the C++20 ostream operator. Since LLVM
887
// uses C++17 it's not possible to use the ostream operator directly.
888
static const std::array<std::string_view, 7> weekdays = {
889
"Sunday", "Monday", "Tuesday", "Wednesday",
890
"Thursday", "Friday", "Saturday"};
891
892
ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__wd_");
893
if (!ptr_sp)
894
return false;
895
896
const unsigned weekday = ptr_sp->GetValueAsUnsigned(0);
897
if (weekday < 7)
898
stream << "weekday=" << weekdays[weekday];
899
else
900
stream.Printf("weekday=%u", weekday);
901
902
return true;
903
}
904
905
bool lldb_private::formatters::LibcxxChronoYearMonthDaySummaryProvider(
906
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
907
ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__y_");
908
if (!ptr_sp)
909
return false;
910
ptr_sp = ptr_sp->GetChildMemberWithName("__y_");
911
if (!ptr_sp)
912
return false;
913
int year = ptr_sp->GetValueAsSigned(0);
914
915
ptr_sp = valobj.GetChildMemberWithName("__m_");
916
if (!ptr_sp)
917
return false;
918
ptr_sp = ptr_sp->GetChildMemberWithName("__m_");
919
if (!ptr_sp)
920
return false;
921
const unsigned month = ptr_sp->GetValueAsUnsigned(0);
922
923
ptr_sp = valobj.GetChildMemberWithName("__d_");
924
if (!ptr_sp)
925
return false;
926
ptr_sp = ptr_sp->GetChildMemberWithName("__d_");
927
if (!ptr_sp)
928
return false;
929
const unsigned day = ptr_sp->GetValueAsUnsigned(0);
930
931
stream << "date=";
932
if (year < 0) {
933
stream << '-';
934
year = -year;
935
}
936
stream.Printf("%04d-%02u-%02u", year, month, day);
937
938
return true;
939
}
940
941