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