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 #include "llvm/ADT/ScopeExit.h" 13 #include "lldb/Core/Debugger.h" 14 #include "lldb/Core/FormatEntity.h" 15 #include "lldb/Core/ValueObject.h" 16 #include "lldb/Core/ValueObjectConstResult.h" 17 #include "lldb/DataFormatters/FormattersHelpers.h" 18 #include "lldb/DataFormatters/StringPrinter.h" 19 #include "lldb/DataFormatters/TypeSummary.h" 20 #include "lldb/DataFormatters/VectorIterator.h" 21 #include "lldb/Symbol/ClangASTContext.h" 22 #include "lldb/Target/CPPLanguageRuntime.h" 23 #include "lldb/Target/ProcessStructReader.h" 24 #include "lldb/Target/SectionLoadList.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Utility/DataBufferHeap.h" 27 #include "lldb/Utility/Endian.h" 28 #include "lldb/Utility/Status.h" 29 #include "lldb/Utility/Stream.h" 30 31 using namespace lldb; 32 using namespace lldb_private; 33 using namespace lldb_private::formatters; 34 35 bool 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 57 bool 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 = process->GetCPPLanguageRuntime(); 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 105 bool 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 170 lldb_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 177 bool 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(__i_->GetCompilerType().GetTypeTemplateArgument(0)); 229 std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr; 230 pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); 231 if (!pair_type) { 232 m_pair_ptr = nullptr; 233 return false; 234 } 235 236 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); 237 m_pair_ptr = nullptr; 238 if (addr && addr!=LLDB_INVALID_ADDRESS) { 239 ClangASTContext *ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); 240 if (!ast_ctx) 241 return false; 242 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), { 243 {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 244 {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 245 {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 246 {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, 247 {"payload",pair_type} 248 }); 249 DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0)); 250 ProcessSP process_sp(target_sp->GetProcessSP()); 251 Status error; 252 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error); 253 if (error.Fail()) 254 return false; 255 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 256 auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type); 257 if (pair_sp) 258 m_pair_sp = pair_sp->GetChildAtIndex(4,true); 259 } 260 } 261 } 262 263 return false; 264 } 265 266 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 267 CalculateNumChildren() { 268 return 2; 269 } 270 271 lldb::ValueObjectSP 272 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 273 size_t idx) { 274 if (m_pair_ptr) 275 return m_pair_ptr->GetChildAtIndex(idx, true); 276 if (m_pair_sp) 277 return m_pair_sp->GetChildAtIndex(idx, true); 278 return lldb::ValueObjectSP(); 279 } 280 281 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 282 MightHaveChildren() { 283 return true; 284 } 285 286 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 287 GetIndexOfChildWithName(const ConstString &name) { 288 if (name == ConstString("first")) 289 return 0; 290 if (name == ConstString("second")) 291 return 1; 292 return UINT32_MAX; 293 } 294 295 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 296 ~LibCxxMapIteratorSyntheticFrontEnd() { 297 // this will be deleted when its parent dies (since it's a child object) 298 // delete m_pair_ptr; 299 } 300 301 SyntheticChildrenFrontEnd * 302 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 303 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 304 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 305 : nullptr); 306 } 307 308 /* 309 (lldb) fr var ibeg --raw --ptr-depth 1 -T 310 (std::__1::__wrap_iter<int *>) ibeg = { 311 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { 312 (int) *__i = 1 313 } 314 } 315 */ 316 317 SyntheticChildrenFrontEnd * 318 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( 319 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 320 static ConstString g_item_name; 321 if (!g_item_name) 322 g_item_name.SetCString("__i"); 323 return (valobj_sp 324 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) 325 : nullptr); 326 } 327 328 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 329 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 330 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(), 331 m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) { 332 if (valobj_sp) 333 Update(); 334 } 335 336 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 337 CalculateNumChildren() { 338 return (m_cntrl ? 1 : 0); 339 } 340 341 lldb::ValueObjectSP 342 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( 343 size_t idx) { 344 if (!m_cntrl) 345 return lldb::ValueObjectSP(); 346 347 ValueObjectSP valobj_sp = m_backend.GetSP(); 348 if (!valobj_sp) 349 return lldb::ValueObjectSP(); 350 351 if (idx == 0) 352 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); 353 354 if (idx > 2) 355 return lldb::ValueObjectSP(); 356 357 if (idx == 1) { 358 if (!m_count_sp) { 359 ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName( 360 ConstString("__shared_owners_"), true)); 361 if (!shared_owners_sp) 362 return lldb::ValueObjectSP(); 363 uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0); 364 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 365 m_count_sp = CreateValueObjectFromData( 366 "count", data, valobj_sp->GetExecutionContextRef(), 367 shared_owners_sp->GetCompilerType()); 368 } 369 return m_count_sp; 370 } else /* if (idx == 2) */ 371 { 372 if (!m_weak_count_sp) { 373 ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName( 374 ConstString("__shared_weak_owners_"), true)); 375 if (!shared_weak_owners_sp) 376 return lldb::ValueObjectSP(); 377 uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0); 378 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 379 m_weak_count_sp = CreateValueObjectFromData( 380 "count", data, valobj_sp->GetExecutionContextRef(), 381 shared_weak_owners_sp->GetCompilerType()); 382 } 383 return m_weak_count_sp; 384 } 385 } 386 387 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { 388 m_count_sp.reset(); 389 m_weak_count_sp.reset(); 390 m_cntrl = nullptr; 391 392 ValueObjectSP valobj_sp = m_backend.GetSP(); 393 if (!valobj_sp) 394 return false; 395 396 TargetSP target_sp(valobj_sp->GetTargetSP()); 397 if (!target_sp) 398 return false; 399 400 m_byte_order = target_sp->GetArchitecture().GetByteOrder(); 401 m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize(); 402 403 lldb::ValueObjectSP cntrl_sp( 404 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); 405 406 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular 407 // dependency 408 return false; 409 } 410 411 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 412 MightHaveChildren() { 413 return true; 414 } 415 416 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 417 GetIndexOfChildWithName(const ConstString &name) { 418 if (name == ConstString("__ptr_")) 419 return 0; 420 if (name == ConstString("count")) 421 return 1; 422 if (name == ConstString("weak_count")) 423 return 2; 424 return UINT32_MAX; 425 } 426 427 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 428 ~LibcxxSharedPtrSyntheticFrontEnd() = default; 429 430 SyntheticChildrenFrontEnd * 431 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( 432 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 433 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp) 434 : nullptr); 435 } 436 437 bool lldb_private::formatters::LibcxxContainerSummaryProvider( 438 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 439 if (valobj.IsPointerType()) { 440 uint64_t value = valobj.GetValueAsUnsigned(0); 441 if (!value) 442 return false; 443 stream.Printf("0x%016" PRIx64 " ", value); 444 } 445 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr, 446 nullptr, nullptr, &valobj, false, false); 447 } 448 449 // the field layout in a libc++ string (cap, side, data or data, size, cap) 450 enum LibcxxStringLayoutMode { 451 eLibcxxStringLayoutModeCSD = 0, 452 eLibcxxStringLayoutModeDSC = 1, 453 eLibcxxStringLayoutModeInvalid = 0xffff 454 }; 455 456 // this function abstracts away the layout and mode details of a libc++ string 457 // and returns the address of the data and the size ready for callers to 458 // consume 459 static bool ExtractLibcxxStringInfo(ValueObject &valobj, 460 ValueObjectSP &location_sp, 461 uint64_t &size) { 462 ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); 463 if (!D) 464 return false; 465 466 ValueObjectSP layout_decider( 467 D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0}))); 468 469 // this child should exist 470 if (!layout_decider) 471 return false; 472 473 ConstString g_data_name("__data_"); 474 ConstString g_size_name("__size_"); 475 bool short_mode = false; // this means the string is in short-mode and the 476 // data is stored inline 477 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) 478 ? eLibcxxStringLayoutModeDSC 479 : eLibcxxStringLayoutModeCSD; 480 uint64_t size_mode_value = 0; 481 482 if (layout == eLibcxxStringLayoutModeDSC) { 483 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); 484 if (!size_mode) 485 return false; 486 487 if (size_mode->GetName() != g_size_name) { 488 // we are hitting the padding structure, move along 489 size_mode = D->GetChildAtIndexPath({1, 1, 1}); 490 if (!size_mode) 491 return false; 492 } 493 494 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 495 short_mode = ((size_mode_value & 0x80) == 0); 496 } else { 497 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); 498 if (!size_mode) 499 return false; 500 501 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 502 short_mode = ((size_mode_value & 1) == 0); 503 } 504 505 if (short_mode) { 506 ValueObjectSP s(D->GetChildAtIndex(1, true)); 507 if (!s) 508 return false; 509 location_sp = s->GetChildAtIndex( 510 (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); 511 size = (layout == eLibcxxStringLayoutModeDSC) 512 ? size_mode_value 513 : ((size_mode_value >> 1) % 256); 514 return (location_sp.get() != nullptr); 515 } else { 516 ValueObjectSP l(D->GetChildAtIndex(0, true)); 517 if (!l) 518 return false; 519 // we can use the layout_decider object as the data pointer 520 location_sp = (layout == eLibcxxStringLayoutModeDSC) 521 ? layout_decider 522 : l->GetChildAtIndex(2, true); 523 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 524 if (!size_vo || !location_sp) 525 return false; 526 size = size_vo->GetValueAsUnsigned(0); 527 return true; 528 } 529 } 530 531 bool lldb_private::formatters::LibcxxWStringSummaryProvider( 532 ValueObject &valobj, Stream &stream, 533 const TypeSummaryOptions &summary_options) { 534 uint64_t size = 0; 535 ValueObjectSP location_sp; 536 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 537 return false; 538 if (size == 0) { 539 stream.Printf("L\"\""); 540 return true; 541 } 542 if (!location_sp) 543 return false; 544 545 DataExtractor extractor; 546 547 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 548 549 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 550 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 551 if (size > max_size) { 552 size = max_size; 553 options.SetIsTruncated(true); 554 } 555 } 556 location_sp->GetPointeeData(extractor, 0, size); 557 558 // std::wstring::size() is measured in 'characters', not bytes 559 auto wchar_t_size = valobj.GetTargetSP() 560 ->GetScratchClangASTContext() 561 ->GetBasicType(lldb::eBasicTypeWChar) 562 .GetByteSize(nullptr); 563 564 options.SetData(extractor); 565 options.SetStream(&stream); 566 options.SetPrefixToken("L"); 567 options.SetQuote('"'); 568 options.SetSourceSize(size); 569 options.SetBinaryZeroIsTerminator(false); 570 571 switch (wchar_t_size) { 572 case 1: 573 StringPrinter::ReadBufferAndDumpToStream< 574 lldb_private::formatters::StringPrinter::StringElementType::UTF8>( 575 options); 576 break; 577 578 case 2: 579 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 580 lldb_private::formatters::StringPrinter::StringElementType::UTF16>( 581 options); 582 break; 583 584 case 4: 585 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 586 lldb_private::formatters::StringPrinter::StringElementType::UTF32>( 587 options); 588 break; 589 590 default: 591 stream.Printf("size for wchar_t is not valid"); 592 return true; 593 } 594 595 return true; 596 } 597 598 template <StringPrinter::StringElementType element_type> 599 bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, 600 const TypeSummaryOptions &summary_options, 601 std::string prefix_token = "") { 602 uint64_t size = 0; 603 ValueObjectSP location_sp; 604 605 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 606 return false; 607 608 if (size == 0) { 609 stream.Printf("\"\""); 610 return true; 611 } 612 613 if (!location_sp) 614 return false; 615 616 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 617 618 DataExtractor extractor; 619 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 620 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 621 if (size > max_size) { 622 size = max_size; 623 options.SetIsTruncated(true); 624 } 625 } 626 location_sp->GetPointeeData(extractor, 0, size); 627 628 options.SetData(extractor); 629 options.SetStream(&stream); 630 631 if (prefix_token.empty()) 632 options.SetPrefixToken(nullptr); 633 else 634 options.SetPrefixToken(prefix_token); 635 636 options.SetQuote('"'); 637 options.SetSourceSize(size); 638 options.SetBinaryZeroIsTerminator(false); 639 StringPrinter::ReadBufferAndDumpToStream<element_type>(options); 640 641 return true; 642 } 643 644 bool lldb_private::formatters::LibcxxStringSummaryProviderASCII( 645 ValueObject &valobj, Stream &stream, 646 const TypeSummaryOptions &summary_options) { 647 return LibcxxStringSummaryProvider<StringPrinter::StringElementType::ASCII>( 648 valobj, stream, summary_options); 649 } 650 651 bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16( 652 ValueObject &valobj, Stream &stream, 653 const TypeSummaryOptions &summary_options) { 654 return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF16>( 655 valobj, stream, summary_options, "u"); 656 } 657 658 bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32( 659 ValueObject &valobj, Stream &stream, 660 const TypeSummaryOptions &summary_options) { 661 return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF32>( 662 valobj, stream, summary_options, "U"); 663 } 664