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