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/ProcessStructReader.h" 20 #include "lldb/Target/SectionLoadList.h" 21 #include "lldb/Target/Target.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 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 = CPPLanguageRuntime::Get(*process); 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 bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( 148 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 149 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 150 if (!valobj_sp) 151 return false; 152 153 ValueObjectSP ptr_sp( 154 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); 155 if (!ptr_sp) 156 return false; 157 158 ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); 159 if (!ptr_sp) 160 return false; 161 162 if (ptr_sp->GetValueAsUnsigned(0) == 0) { 163 stream.Printf("nullptr"); 164 return true; 165 } else { 166 bool print_pointee = false; 167 Status error; 168 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 169 if (pointee_sp && error.Success()) { 170 if (pointee_sp->DumpPrintableRepresentation( 171 stream, ValueObject::eValueObjectRepresentationStyleSummary, 172 lldb::eFormatInvalid, 173 ValueObject::PrintableRepresentationSpecialCases::eDisable, 174 false)) 175 print_pointee = true; 176 } 177 if (!print_pointee) 178 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 179 } 180 181 return true; 182 } 183 184 /* 185 (lldb) fr var ibeg --raw --ptr-depth 1 186 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, 187 std::__1::basic_string<char, std::__1::char_traits<char>, 188 std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, 189 std::__1::basic_string<char, std::__1::char_traits<char>, 190 std::__1::allocator<char> > >, void *> *, long> >) ibeg = { 191 __i_ = { 192 __ptr_ = 0x0000000100103870 { 193 std::__1::__tree_node_base<void *> = { 194 std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = { 195 __left_ = 0x0000000000000000 196 } 197 __right_ = 0x0000000000000000 198 __parent_ = 0x00000001001038b0 199 __is_black_ = true 200 } 201 __value_ = { 202 first = 0 203 second = { std::string } 204 */ 205 206 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 207 LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 208 : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { 209 if (valobj_sp) 210 Update(); 211 } 212 213 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { 214 m_pair_sp.reset(); 215 m_pair_ptr = nullptr; 216 217 ValueObjectSP valobj_sp = m_backend.GetSP(); 218 if (!valobj_sp) 219 return false; 220 221 TargetSP target_sp(valobj_sp->GetTargetSP()); 222 223 if (!target_sp) 224 return false; 225 226 if (!valobj_sp) 227 return false; 228 229 static ConstString g___i_("__i_"); 230 231 // this must be a ValueObject* because it is a child of the ValueObject we 232 // are producing children for it if were a ValueObjectSP, we would end up 233 // with a loop (iterator -> synthetic -> child -> parent == iterator) and 234 // that would in turn leak memory by never allowing the ValueObjects to die 235 // and free their memory 236 m_pair_ptr = valobj_sp 237 ->GetValueForExpressionPath( 238 ".__i_.__ptr_->__value_", nullptr, nullptr, 239 ValueObject::GetValueForExpressionPathOptions() 240 .DontCheckDotVsArrowSyntax() 241 .SetSyntheticChildrenTraversal( 242 ValueObject::GetValueForExpressionPathOptions:: 243 SyntheticChildrenTraversal::None), 244 nullptr) 245 .get(); 246 247 if (!m_pair_ptr) { 248 m_pair_ptr = valobj_sp 249 ->GetValueForExpressionPath( 250 ".__i_.__ptr_", nullptr, nullptr, 251 ValueObject::GetValueForExpressionPathOptions() 252 .DontCheckDotVsArrowSyntax() 253 .SetSyntheticChildrenTraversal( 254 ValueObject::GetValueForExpressionPathOptions:: 255 SyntheticChildrenTraversal::None), 256 nullptr) 257 .get(); 258 if (m_pair_ptr) { 259 auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true)); 260 if (!__i_) { 261 m_pair_ptr = nullptr; 262 return false; 263 } 264 CompilerType pair_type( 265 __i_->GetCompilerType().GetTypeTemplateArgument(0)); 266 std::string name; 267 uint64_t bit_offset_ptr; 268 uint32_t bitfield_bit_size_ptr; 269 bool is_bitfield_ptr; 270 pair_type = pair_type.GetFieldAtIndex( 271 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); 272 if (!pair_type) { 273 m_pair_ptr = nullptr; 274 return false; 275 } 276 277 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); 278 m_pair_ptr = nullptr; 279 if (addr && addr != LLDB_INVALID_ADDRESS) { 280 TypeSystemClang *ast_ctx = 281 llvm::dyn_cast_or_null<TypeSystemClang>(pair_type.GetTypeSystem()); 282 if (!ast_ctx) 283 return false; 284 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( 285 ConstString(), 286 {{"ptr0", 287 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 288 {"ptr1", 289 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 290 {"ptr2", 291 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 292 {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, 293 {"payload", pair_type}}); 294 llvm::Optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); 295 if (!size) 296 return false; 297 DataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); 298 ProcessSP process_sp(target_sp->GetProcessSP()); 299 Status error; 300 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), 301 buffer_sp->GetByteSize(), error); 302 if (error.Fail()) 303 return false; 304 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), 305 process_sp->GetAddressByteSize()); 306 auto pair_sp = CreateValueObjectFromData( 307 "pair", extractor, valobj_sp->GetExecutionContextRef(), 308 tree_node_type); 309 if (pair_sp) 310 m_pair_sp = pair_sp->GetChildAtIndex(4, true); 311 } 312 } 313 } 314 315 return false; 316 } 317 318 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 319 CalculateNumChildren() { 320 return 2; 321 } 322 323 lldb::ValueObjectSP 324 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 325 size_t idx) { 326 if (m_pair_ptr) 327 return m_pair_ptr->GetChildAtIndex(idx, true); 328 if (m_pair_sp) 329 return m_pair_sp->GetChildAtIndex(idx, true); 330 return lldb::ValueObjectSP(); 331 } 332 333 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 334 MightHaveChildren() { 335 return true; 336 } 337 338 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 339 GetIndexOfChildWithName(ConstString name) { 340 if (name == "first") 341 return 0; 342 if (name == "second") 343 return 1; 344 return UINT32_MAX; 345 } 346 347 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 348 ~LibCxxMapIteratorSyntheticFrontEnd() { 349 // this will be deleted when its parent dies (since it's a child object) 350 // delete m_pair_ptr; 351 } 352 353 SyntheticChildrenFrontEnd * 354 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 355 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 356 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 357 : nullptr); 358 } 359 360 /* 361 (lldb) fr var ibeg --raw --ptr-depth 1 -T 362 (std::__1::__wrap_iter<int *>) ibeg = { 363 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { 364 (int) *__i = 1 365 } 366 } 367 */ 368 369 SyntheticChildrenFrontEnd * 370 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( 371 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 372 static ConstString g_item_name; 373 if (!g_item_name) 374 g_item_name.SetCString("__i"); 375 return (valobj_sp 376 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) 377 : nullptr); 378 } 379 380 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 381 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 382 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr) { 383 if (valobj_sp) 384 Update(); 385 } 386 387 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 388 CalculateNumChildren() { 389 return (m_cntrl ? 1 : 0); 390 } 391 392 lldb::ValueObjectSP 393 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( 394 size_t idx) { 395 if (!m_cntrl) 396 return lldb::ValueObjectSP(); 397 398 ValueObjectSP valobj_sp = m_backend.GetSP(); 399 if (!valobj_sp) 400 return lldb::ValueObjectSP(); 401 402 if (idx == 0) 403 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); 404 405 if (idx == 1) { 406 if (auto ptr_sp = 407 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)) { 408 Status status; 409 auto value_sp = ptr_sp->Dereference(status); 410 if (status.Success()) { 411 auto value_type_sp = 412 valobj_sp->GetCompilerType().GetTypeTemplateArgument(0); 413 return value_sp->Cast(value_type_sp); 414 } 415 } 416 } 417 418 return lldb::ValueObjectSP(); 419 } 420 421 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { 422 m_cntrl = nullptr; 423 424 ValueObjectSP valobj_sp = m_backend.GetSP(); 425 if (!valobj_sp) 426 return false; 427 428 TargetSP target_sp(valobj_sp->GetTargetSP()); 429 if (!target_sp) 430 return false; 431 432 lldb::ValueObjectSP cntrl_sp( 433 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); 434 435 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular 436 // dependency 437 return false; 438 } 439 440 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 441 MightHaveChildren() { 442 return true; 443 } 444 445 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 446 GetIndexOfChildWithName(ConstString name) { 447 if (name == "__ptr_") 448 return 0; 449 if (name == "$$dereference$$") 450 return 1; 451 return UINT32_MAX; 452 } 453 454 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 455 ~LibcxxSharedPtrSyntheticFrontEnd() = default; 456 457 SyntheticChildrenFrontEnd * 458 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( 459 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 460 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp) 461 : nullptr); 462 } 463 464 lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 465 LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 466 : SyntheticChildrenFrontEnd(*valobj_sp) { 467 if (valobj_sp) 468 Update(); 469 } 470 471 lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 472 ~LibcxxUniquePtrSyntheticFrontEnd() = default; 473 474 SyntheticChildrenFrontEnd * 475 lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator( 476 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 477 return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp) 478 : nullptr); 479 } 480 481 size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 482 CalculateNumChildren() { 483 return (m_value_ptr_sp ? 1 : 0); 484 } 485 486 lldb::ValueObjectSP 487 lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex( 488 size_t idx) { 489 if (!m_value_ptr_sp) 490 return lldb::ValueObjectSP(); 491 492 if (idx == 0) 493 return m_value_ptr_sp; 494 495 if (idx == 1) { 496 Status status; 497 auto value_sp = m_value_ptr_sp->Dereference(status); 498 if (status.Success()) { 499 return value_sp; 500 } 501 } 502 503 return lldb::ValueObjectSP(); 504 } 505 506 bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { 507 ValueObjectSP valobj_sp = m_backend.GetSP(); 508 if (!valobj_sp) 509 return false; 510 511 ValueObjectSP ptr_sp( 512 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); 513 if (!ptr_sp) 514 return false; 515 516 m_value_ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); 517 518 return false; 519 } 520 521 bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 522 MightHaveChildren() { 523 return true; 524 } 525 526 size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 527 GetIndexOfChildWithName(ConstString name) { 528 if (name == "__value_") 529 return 0; 530 if (name == "$$dereference$$") 531 return 1; 532 return UINT32_MAX; 533 } 534 535 bool lldb_private::formatters::LibcxxContainerSummaryProvider( 536 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 537 if (valobj.IsPointerType()) { 538 uint64_t value = valobj.GetValueAsUnsigned(0); 539 if (!value) 540 return false; 541 stream.Printf("0x%016" PRIx64 " ", value); 542 } 543 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr, 544 nullptr, nullptr, &valobj, false, false); 545 } 546 547 // the field layout in a libc++ string (cap, side, data or data, size, cap) 548 enum LibcxxStringLayoutMode { 549 eLibcxxStringLayoutModeCSD = 0, 550 eLibcxxStringLayoutModeDSC = 1, 551 eLibcxxStringLayoutModeInvalid = 0xffff 552 }; 553 554 /// Determine the size in bytes of \p valobj (a libc++ std::string object) and 555 /// extract its data payload. Return the size + payload pair. 556 static llvm::Optional<std::pair<uint64_t, ValueObjectSP>> 557 ExtractLibcxxStringInfo(ValueObject &valobj) { 558 ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); 559 if (!D) 560 return {}; 561 562 ValueObjectSP layout_decider( 563 D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0}))); 564 565 // this child should exist 566 if (!layout_decider) 567 return {}; 568 569 ConstString g_data_name("__data_"); 570 ConstString g_size_name("__size_"); 571 bool short_mode = false; // this means the string is in short-mode and the 572 // data is stored inline 573 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) 574 ? eLibcxxStringLayoutModeDSC 575 : eLibcxxStringLayoutModeCSD; 576 uint64_t size_mode_value = 0; 577 578 if (layout == eLibcxxStringLayoutModeDSC) { 579 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); 580 if (!size_mode) 581 return {}; 582 583 if (size_mode->GetName() != g_size_name) { 584 // we are hitting the padding structure, move along 585 size_mode = D->GetChildAtIndexPath({1, 1, 1}); 586 if (!size_mode) 587 return {}; 588 } 589 590 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 591 short_mode = ((size_mode_value & 0x80) == 0); 592 } else { 593 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); 594 if (!size_mode) 595 return {}; 596 597 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 598 short_mode = ((size_mode_value & 1) == 0); 599 } 600 601 if (short_mode) { 602 ValueObjectSP s(D->GetChildAtIndex(1, true)); 603 if (!s) 604 return {}; 605 ValueObjectSP location_sp = s->GetChildAtIndex( 606 (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); 607 const uint64_t size = (layout == eLibcxxStringLayoutModeDSC) 608 ? size_mode_value 609 : ((size_mode_value >> 1) % 256); 610 611 // When the small-string optimization takes place, the data must fit in the 612 // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's 613 // likely that the string isn't initialized and we're reading garbage. 614 ExecutionContext exe_ctx(location_sp->GetExecutionContextRef()); 615 const llvm::Optional<uint64_t> max_bytes = 616 location_sp->GetCompilerType().GetByteSize( 617 exe_ctx.GetBestExecutionContextScope()); 618 if (!max_bytes || size > *max_bytes || !location_sp) 619 return {}; 620 621 return std::make_pair(size, location_sp); 622 } 623 624 ValueObjectSP l(D->GetChildAtIndex(0, true)); 625 if (!l) 626 return {}; 627 // we can use the layout_decider object as the data pointer 628 ValueObjectSP location_sp = (layout == eLibcxxStringLayoutModeDSC) 629 ? layout_decider 630 : l->GetChildAtIndex(2, true); 631 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 632 const unsigned capacity_index = 633 (layout == eLibcxxStringLayoutModeDSC) ? 2 : 0; 634 ValueObjectSP capacity_vo(l->GetChildAtIndex(capacity_index, true)); 635 if (!size_vo || !location_sp || !capacity_vo) 636 return {}; 637 const uint64_t size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); 638 const uint64_t capacity = 639 capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); 640 if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET || 641 capacity < size) 642 return {}; 643 return std::make_pair(size, location_sp); 644 } 645 646 bool lldb_private::formatters::LibcxxWStringSummaryProvider( 647 ValueObject &valobj, Stream &stream, 648 const TypeSummaryOptions &summary_options) { 649 auto string_info = ExtractLibcxxStringInfo(valobj); 650 if (!string_info) 651 return false; 652 uint64_t size; 653 ValueObjectSP location_sp; 654 std::tie(size, location_sp) = *string_info; 655 656 if (size == 0) { 657 stream.Printf("L\"\""); 658 return true; 659 } 660 if (!location_sp) 661 return false; 662 663 664 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 665 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 666 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 667 if (size > max_size) { 668 size = max_size; 669 options.SetIsTruncated(true); 670 } 671 } 672 673 DataExtractor extractor; 674 const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); 675 if (bytes_read < size) 676 return false; 677 678 // std::wstring::size() is measured in 'characters', not bytes 679 TypeSystemClang *ast_context = 680 ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP()); 681 if (!ast_context) 682 return false; 683 684 auto wchar_t_size = 685 ast_context->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr); 686 if (!wchar_t_size) 687 return false; 688 689 options.SetData(extractor); 690 options.SetStream(&stream); 691 options.SetPrefixToken("L"); 692 options.SetQuote('"'); 693 options.SetSourceSize(size); 694 options.SetBinaryZeroIsTerminator(false); 695 696 switch (*wchar_t_size) { 697 case 1: 698 return StringPrinter::ReadBufferAndDumpToStream< 699 lldb_private::formatters::StringPrinter::StringElementType::UTF8>( 700 options); 701 break; 702 703 case 2: 704 return StringPrinter::ReadBufferAndDumpToStream< 705 lldb_private::formatters::StringPrinter::StringElementType::UTF16>( 706 options); 707 break; 708 709 case 4: 710 return StringPrinter::ReadBufferAndDumpToStream< 711 lldb_private::formatters::StringPrinter::StringElementType::UTF32>( 712 options); 713 } 714 return false; 715 } 716 717 template <StringPrinter::StringElementType element_type> 718 bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, 719 const TypeSummaryOptions &summary_options, 720 std::string prefix_token) { 721 auto string_info = ExtractLibcxxStringInfo(valobj); 722 if (!string_info) 723 return false; 724 uint64_t size; 725 ValueObjectSP location_sp; 726 std::tie(size, location_sp) = *string_info; 727 728 if (size == 0) { 729 stream.Printf("\"\""); 730 return true; 731 } 732 733 if (!location_sp) 734 return false; 735 736 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 737 738 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 739 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 740 if (size > max_size) { 741 size = max_size; 742 options.SetIsTruncated(true); 743 } 744 } 745 746 DataExtractor extractor; 747 const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); 748 if (bytes_read < size) 749 return false; 750 751 options.SetData(extractor); 752 options.SetStream(&stream); 753 if (prefix_token.empty()) 754 options.SetPrefixToken(nullptr); 755 else 756 options.SetPrefixToken(prefix_token); 757 options.SetQuote('"'); 758 options.SetSourceSize(size); 759 options.SetBinaryZeroIsTerminator(false); 760 return StringPrinter::ReadBufferAndDumpToStream<element_type>(options); 761 } 762 763 template <StringPrinter::StringElementType element_type> 764 static bool formatStringImpl(ValueObject &valobj, Stream &stream, 765 const TypeSummaryOptions &summary_options, 766 std::string prefix_token) { 767 StreamString scratch_stream; 768 const bool success = LibcxxStringSummaryProvider<element_type>( 769 valobj, scratch_stream, summary_options, prefix_token); 770 if (success) 771 stream << scratch_stream.GetData(); 772 else 773 stream << "Summary Unavailable"; 774 return true; 775 } 776 777 bool lldb_private::formatters::LibcxxStringSummaryProviderASCII( 778 ValueObject &valobj, Stream &stream, 779 const TypeSummaryOptions &summary_options) { 780 return formatStringImpl<StringPrinter::StringElementType::ASCII>( 781 valobj, stream, summary_options, ""); 782 } 783 784 bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16( 785 ValueObject &valobj, Stream &stream, 786 const TypeSummaryOptions &summary_options) { 787 return formatStringImpl<StringPrinter::StringElementType::UTF16>( 788 valobj, stream, summary_options, "u"); 789 } 790 791 bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32( 792 ValueObject &valobj, Stream &stream, 793 const TypeSummaryOptions &summary_options) { 794 return formatStringImpl<StringPrinter::StringElementType::UTF32>( 795 valobj, stream, summary_options, "U"); 796 } 797