1 //===-- LibCxx.cpp ----------------------------------------------*- C++ -*-===// 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 "llvm/ADT/ScopeExit.h" 12 #include "lldb/Core/Debugger.h" 13 #include "lldb/Core/FormatEntity.h" 14 #include "lldb/Core/ValueObject.h" 15 #include "lldb/Core/ValueObjectConstResult.h" 16 #include "lldb/DataFormatters/FormattersHelpers.h" 17 #include "lldb/DataFormatters/StringPrinter.h" 18 #include "lldb/DataFormatters/TypeSummary.h" 19 #include "lldb/DataFormatters/VectorIterator.h" 20 #include "lldb/Symbol/ClangASTContext.h" 21 #include "lldb/Target/CPPLanguageRuntime.h" 22 #include "lldb/Target/ProcessStructReader.h" 23 #include "lldb/Target/SectionLoadList.h" 24 #include "lldb/Target/Target.h" 25 #include "lldb/Utility/DataBufferHeap.h" 26 #include "lldb/Utility/Endian.h" 27 #include "lldb/Utility/Status.h" 28 #include "lldb/Utility/Stream.h" 29 30 using namespace lldb; 31 using namespace lldb_private; 32 using namespace lldb_private::formatters; 33 34 bool lldb_private::formatters::LibcxxOptionalSummaryProvider( 35 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 36 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 37 if (!valobj_sp) 38 return false; 39 40 // An optional either contains a value or not, the member __engaged_ is 41 // a bool flag, it is true if the optional has a value and false otherwise. 42 ValueObjectSP engaged_sp( 43 valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true)); 44 45 if (!engaged_sp) 46 return false; 47 48 llvm::StringRef engaged_as_cstring( 49 engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false"); 50 51 stream.Printf(" Has Value=%s ", engaged_as_cstring.data()); 52 53 return true; 54 } 55 56 bool lldb_private::formatters::LibcxxFunctionSummaryProvider( 57 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 58 59 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 60 61 if (!valobj_sp) 62 return false; 63 64 ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); 65 Process *process = exe_ctx.GetProcessPtr(); 66 67 if (process == nullptr) 68 return false; 69 70 CPPLanguageRuntime *cpp_runtime = process->GetCPPLanguageRuntime(); 71 72 if (!cpp_runtime) 73 return false; 74 75 CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info = 76 cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp); 77 78 switch (callable_info.callable_case) { 79 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid: 80 stream.Printf(" __f_ = %" PRIu64, callable_info.member__f_pointer_value); 81 return false; 82 break; 83 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda: 84 stream.Printf( 85 " Lambda in File %s at Line %u", 86 callable_info.callable_line_entry.file.GetFilename().GetCString(), 87 callable_info.callable_line_entry.line); 88 break; 89 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject: 90 stream.Printf( 91 " Function in File %s at Line %u", 92 callable_info.callable_line_entry.file.GetFilename().GetCString(), 93 callable_info.callable_line_entry.line); 94 break; 95 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction: 96 stream.Printf(" Function = %s ", 97 callable_info.callable_symbol.GetName().GetCString()); 98 break; 99 } 100 101 return true; 102 } 103 104 bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( 105 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 106 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 107 if (!valobj_sp) 108 return false; 109 ValueObjectSP ptr_sp( 110 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); 111 ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath( 112 {ConstString("__cntrl_"), ConstString("__shared_owners_")})); 113 ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath( 114 {ConstString("__cntrl_"), ConstString("__shared_weak_owners_")})); 115 116 if (!ptr_sp) 117 return false; 118 119 if (ptr_sp->GetValueAsUnsigned(0) == 0) { 120 stream.Printf("nullptr"); 121 return true; 122 } else { 123 bool print_pointee = false; 124 Status error; 125 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 126 if (pointee_sp && error.Success()) { 127 if (pointee_sp->DumpPrintableRepresentation( 128 stream, ValueObject::eValueObjectRepresentationStyleSummary, 129 lldb::eFormatInvalid, 130 ValueObject::PrintableRepresentationSpecialCases::eDisable, 131 false)) 132 print_pointee = true; 133 } 134 if (!print_pointee) 135 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 136 } 137 138 if (count_sp) 139 stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0)); 140 141 if (weakcount_sp) 142 stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0)); 143 144 return true; 145 } 146 147 /* 148 (lldb) fr var ibeg --raw --ptr-depth 1 149 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, 150 std::__1::basic_string<char, std::__1::char_traits<char>, 151 std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, 152 std::__1::basic_string<char, std::__1::char_traits<char>, 153 std::__1::allocator<char> > >, void *> *, long> >) ibeg = { 154 __i_ = { 155 __ptr_ = 0x0000000100103870 { 156 std::__1::__tree_node_base<void *> = { 157 std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = { 158 __left_ = 0x0000000000000000 159 } 160 __right_ = 0x0000000000000000 161 __parent_ = 0x00000001001038b0 162 __is_black_ = true 163 } 164 __value_ = { 165 first = 0 166 second = { std::string } 167 */ 168 169 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 170 LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 171 : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { 172 if (valobj_sp) 173 Update(); 174 } 175 176 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { 177 m_pair_sp.reset(); 178 m_pair_ptr = nullptr; 179 180 ValueObjectSP valobj_sp = m_backend.GetSP(); 181 if (!valobj_sp) 182 return false; 183 184 TargetSP target_sp(valobj_sp->GetTargetSP()); 185 186 if (!target_sp) 187 return false; 188 189 if (!valobj_sp) 190 return false; 191 192 static ConstString g___i_("__i_"); 193 194 // this must be a ValueObject* because it is a child of the ValueObject we 195 // are producing children for it if were a ValueObjectSP, we would end up 196 // with a loop (iterator -> synthetic -> child -> parent == iterator) and 197 // that would in turn leak memory by never allowing the ValueObjects to die 198 // and free their memory 199 m_pair_ptr = valobj_sp 200 ->GetValueForExpressionPath( 201 ".__i_.__ptr_->__value_", nullptr, nullptr, 202 ValueObject::GetValueForExpressionPathOptions() 203 .DontCheckDotVsArrowSyntax() 204 .SetSyntheticChildrenTraversal( 205 ValueObject::GetValueForExpressionPathOptions:: 206 SyntheticChildrenTraversal::None), 207 nullptr) 208 .get(); 209 210 if (!m_pair_ptr) { 211 m_pair_ptr = valobj_sp 212 ->GetValueForExpressionPath( 213 ".__i_.__ptr_", nullptr, nullptr, 214 ValueObject::GetValueForExpressionPathOptions() 215 .DontCheckDotVsArrowSyntax() 216 .SetSyntheticChildrenTraversal( 217 ValueObject::GetValueForExpressionPathOptions:: 218 SyntheticChildrenTraversal::None), 219 nullptr) 220 .get(); 221 if (m_pair_ptr) { 222 auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true)); 223 if (!__i_) { 224 m_pair_ptr = nullptr; 225 return false; 226 } 227 CompilerType pair_type( 228 __i_->GetCompilerType().GetTypeTemplateArgument(0)); 229 std::string name; 230 uint64_t bit_offset_ptr; 231 uint32_t bitfield_bit_size_ptr; 232 bool is_bitfield_ptr; 233 pair_type = pair_type.GetFieldAtIndex( 234 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); 235 if (!pair_type) { 236 m_pair_ptr = nullptr; 237 return false; 238 } 239 240 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); 241 m_pair_ptr = nullptr; 242 if (addr && addr != LLDB_INVALID_ADDRESS) { 243 ClangASTContext *ast_ctx = 244 llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); 245 if (!ast_ctx) 246 return false; 247 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( 248 ConstString(), 249 {{"ptr0", 250 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 251 {"ptr1", 252 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 253 {"ptr2", 254 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 255 {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, 256 {"payload", pair_type}}); 257 llvm::Optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); 258 if (!size) 259 return false; 260 DataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); 261 ProcessSP process_sp(target_sp->GetProcessSP()); 262 Status error; 263 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), 264 buffer_sp->GetByteSize(), error); 265 if (error.Fail()) 266 return false; 267 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), 268 process_sp->GetAddressByteSize()); 269 auto pair_sp = CreateValueObjectFromData( 270 "pair", extractor, valobj_sp->GetExecutionContextRef(), 271 tree_node_type); 272 if (pair_sp) 273 m_pair_sp = pair_sp->GetChildAtIndex(4, true); 274 } 275 } 276 } 277 278 return false; 279 } 280 281 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 282 CalculateNumChildren() { 283 return 2; 284 } 285 286 lldb::ValueObjectSP 287 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 288 size_t idx) { 289 if (m_pair_ptr) 290 return m_pair_ptr->GetChildAtIndex(idx, true); 291 if (m_pair_sp) 292 return m_pair_sp->GetChildAtIndex(idx, true); 293 return lldb::ValueObjectSP(); 294 } 295 296 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 297 MightHaveChildren() { 298 return true; 299 } 300 301 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 302 GetIndexOfChildWithName(ConstString name) { 303 if (name == ConstString("first")) 304 return 0; 305 if (name == ConstString("second")) 306 return 1; 307 return UINT32_MAX; 308 } 309 310 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 311 ~LibCxxMapIteratorSyntheticFrontEnd() { 312 // this will be deleted when its parent dies (since it's a child object) 313 // delete m_pair_ptr; 314 } 315 316 SyntheticChildrenFrontEnd * 317 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 318 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 319 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 320 : nullptr); 321 } 322 323 /* 324 (lldb) fr var ibeg --raw --ptr-depth 1 -T 325 (std::__1::__wrap_iter<int *>) ibeg = { 326 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { 327 (int) *__i = 1 328 } 329 } 330 */ 331 332 SyntheticChildrenFrontEnd * 333 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( 334 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 335 static ConstString g_item_name; 336 if (!g_item_name) 337 g_item_name.SetCString("__i"); 338 return (valobj_sp 339 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) 340 : nullptr); 341 } 342 343 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 344 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 345 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(), 346 m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) { 347 if (valobj_sp) 348 Update(); 349 } 350 351 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 352 CalculateNumChildren() { 353 return (m_cntrl ? 1 : 0); 354 } 355 356 lldb::ValueObjectSP 357 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( 358 size_t idx) { 359 if (!m_cntrl) 360 return lldb::ValueObjectSP(); 361 362 ValueObjectSP valobj_sp = m_backend.GetSP(); 363 if (!valobj_sp) 364 return lldb::ValueObjectSP(); 365 366 if (idx == 0) 367 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); 368 369 if (idx > 2) 370 return lldb::ValueObjectSP(); 371 372 if (idx == 1) { 373 if (!m_count_sp) { 374 ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName( 375 ConstString("__shared_owners_"), true)); 376 if (!shared_owners_sp) 377 return lldb::ValueObjectSP(); 378 uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0); 379 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 380 m_count_sp = CreateValueObjectFromData( 381 "count", data, valobj_sp->GetExecutionContextRef(), 382 shared_owners_sp->GetCompilerType()); 383 } 384 return m_count_sp; 385 } else /* if (idx == 2) */ 386 { 387 if (!m_weak_count_sp) { 388 ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName( 389 ConstString("__shared_weak_owners_"), true)); 390 if (!shared_weak_owners_sp) 391 return lldb::ValueObjectSP(); 392 uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0); 393 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 394 m_weak_count_sp = CreateValueObjectFromData( 395 "count", data, valobj_sp->GetExecutionContextRef(), 396 shared_weak_owners_sp->GetCompilerType()); 397 } 398 return m_weak_count_sp; 399 } 400 } 401 402 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { 403 m_count_sp.reset(); 404 m_weak_count_sp.reset(); 405 m_cntrl = nullptr; 406 407 ValueObjectSP valobj_sp = m_backend.GetSP(); 408 if (!valobj_sp) 409 return false; 410 411 TargetSP target_sp(valobj_sp->GetTargetSP()); 412 if (!target_sp) 413 return false; 414 415 m_byte_order = target_sp->GetArchitecture().GetByteOrder(); 416 m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize(); 417 418 lldb::ValueObjectSP cntrl_sp( 419 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); 420 421 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular 422 // dependency 423 return false; 424 } 425 426 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 427 MightHaveChildren() { 428 return true; 429 } 430 431 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 432 GetIndexOfChildWithName(ConstString name) { 433 if (name == ConstString("__ptr_")) 434 return 0; 435 if (name == ConstString("count")) 436 return 1; 437 if (name == ConstString("weak_count")) 438 return 2; 439 return UINT32_MAX; 440 } 441 442 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 443 ~LibcxxSharedPtrSyntheticFrontEnd() = default; 444 445 SyntheticChildrenFrontEnd * 446 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( 447 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 448 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp) 449 : nullptr); 450 } 451 452 bool lldb_private::formatters::LibcxxContainerSummaryProvider( 453 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 454 if (valobj.IsPointerType()) { 455 uint64_t value = valobj.GetValueAsUnsigned(0); 456 if (!value) 457 return false; 458 stream.Printf("0x%016" PRIx64 " ", value); 459 } 460 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr, 461 nullptr, nullptr, &valobj, false, false); 462 } 463 464 // the field layout in a libc++ string (cap, side, data or data, size, cap) 465 enum LibcxxStringLayoutMode { 466 eLibcxxStringLayoutModeCSD = 0, 467 eLibcxxStringLayoutModeDSC = 1, 468 eLibcxxStringLayoutModeInvalid = 0xffff 469 }; 470 471 // this function abstracts away the layout and mode details of a libc++ string 472 // and returns the address of the data and the size ready for callers to 473 // consume 474 static bool ExtractLibcxxStringInfo(ValueObject &valobj, 475 ValueObjectSP &location_sp, 476 uint64_t &size) { 477 ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); 478 if (!D) 479 return false; 480 481 ValueObjectSP layout_decider( 482 D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0}))); 483 484 // this child should exist 485 if (!layout_decider) 486 return false; 487 488 ConstString g_data_name("__data_"); 489 ConstString g_size_name("__size_"); 490 bool short_mode = false; // this means the string is in short-mode and the 491 // data is stored inline 492 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) 493 ? eLibcxxStringLayoutModeDSC 494 : eLibcxxStringLayoutModeCSD; 495 uint64_t size_mode_value = 0; 496 497 if (layout == eLibcxxStringLayoutModeDSC) { 498 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); 499 if (!size_mode) 500 return false; 501 502 if (size_mode->GetName() != g_size_name) { 503 // we are hitting the padding structure, move along 504 size_mode = D->GetChildAtIndexPath({1, 1, 1}); 505 if (!size_mode) 506 return false; 507 } 508 509 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 510 short_mode = ((size_mode_value & 0x80) == 0); 511 } else { 512 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); 513 if (!size_mode) 514 return false; 515 516 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 517 short_mode = ((size_mode_value & 1) == 0); 518 } 519 520 if (short_mode) { 521 ValueObjectSP s(D->GetChildAtIndex(1, true)); 522 if (!s) 523 return false; 524 location_sp = s->GetChildAtIndex( 525 (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); 526 size = (layout == eLibcxxStringLayoutModeDSC) 527 ? size_mode_value 528 : ((size_mode_value >> 1) % 256); 529 return (location_sp.get() != nullptr); 530 } else { 531 ValueObjectSP l(D->GetChildAtIndex(0, true)); 532 if (!l) 533 return false; 534 // we can use the layout_decider object as the data pointer 535 location_sp = (layout == eLibcxxStringLayoutModeDSC) 536 ? layout_decider 537 : l->GetChildAtIndex(2, true); 538 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 539 if (!size_vo || !location_sp) 540 return false; 541 size = size_vo->GetValueAsUnsigned(0); 542 return true; 543 } 544 } 545 546 bool lldb_private::formatters::LibcxxWStringSummaryProvider( 547 ValueObject &valobj, Stream &stream, 548 const TypeSummaryOptions &summary_options) { 549 uint64_t size = 0; 550 ValueObjectSP location_sp; 551 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 552 return false; 553 if (size == 0) { 554 stream.Printf("L\"\""); 555 return true; 556 } 557 if (!location_sp) 558 return false; 559 560 DataExtractor extractor; 561 562 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 563 564 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 565 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 566 if (size > max_size) { 567 size = max_size; 568 options.SetIsTruncated(true); 569 } 570 } 571 location_sp->GetPointeeData(extractor, 0, size); 572 573 // std::wstring::size() is measured in 'characters', not bytes 574 auto wchar_t_size = valobj.GetTargetSP() 575 ->GetScratchClangASTContext() 576 ->GetBasicType(lldb::eBasicTypeWChar) 577 .GetByteSize(nullptr); 578 if (!wchar_t_size) 579 return false; 580 581 options.SetData(extractor); 582 options.SetStream(&stream); 583 options.SetPrefixToken("L"); 584 options.SetQuote('"'); 585 options.SetSourceSize(size); 586 options.SetBinaryZeroIsTerminator(false); 587 588 switch (*wchar_t_size) { 589 case 1: 590 StringPrinter::ReadBufferAndDumpToStream< 591 lldb_private::formatters::StringPrinter::StringElementType::UTF8>( 592 options); 593 break; 594 595 case 2: 596 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 597 lldb_private::formatters::StringPrinter::StringElementType::UTF16>( 598 options); 599 break; 600 601 case 4: 602 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 603 lldb_private::formatters::StringPrinter::StringElementType::UTF32>( 604 options); 605 break; 606 607 default: 608 stream.Printf("size for wchar_t is not valid"); 609 return true; 610 } 611 612 return true; 613 } 614 615 template <StringPrinter::StringElementType element_type> 616 bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, 617 const TypeSummaryOptions &summary_options, 618 std::string prefix_token = "") { 619 uint64_t size = 0; 620 ValueObjectSP location_sp; 621 622 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 623 return false; 624 625 if (size == 0) { 626 stream.Printf("\"\""); 627 return true; 628 } 629 630 if (!location_sp) 631 return false; 632 633 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 634 635 DataExtractor extractor; 636 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 637 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 638 if (size > max_size) { 639 size = max_size; 640 options.SetIsTruncated(true); 641 } 642 } 643 location_sp->GetPointeeData(extractor, 0, size); 644 645 options.SetData(extractor); 646 options.SetStream(&stream); 647 648 if (prefix_token.empty()) 649 options.SetPrefixToken(nullptr); 650 else 651 options.SetPrefixToken(prefix_token); 652 653 options.SetQuote('"'); 654 options.SetSourceSize(size); 655 options.SetBinaryZeroIsTerminator(false); 656 StringPrinter::ReadBufferAndDumpToStream<element_type>(options); 657 658 return true; 659 } 660 661 bool lldb_private::formatters::LibcxxStringSummaryProviderASCII( 662 ValueObject &valobj, Stream &stream, 663 const TypeSummaryOptions &summary_options) { 664 return LibcxxStringSummaryProvider<StringPrinter::StringElementType::ASCII>( 665 valobj, stream, summary_options); 666 } 667 668 bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16( 669 ValueObject &valobj, Stream &stream, 670 const TypeSummaryOptions &summary_options) { 671 return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF16>( 672 valobj, stream, summary_options, "u"); 673 } 674 675 bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32( 676 ValueObject &valobj, Stream &stream, 677 const TypeSummaryOptions &summary_options) { 678 return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF32>( 679 valobj, stream, summary_options, "U"); 680 } 681