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