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/ConstString.h" 23 #include "lldb/Utility/DataBufferHeap.h" 24 #include "lldb/Utility/Endian.h" 25 #include "lldb/Utility/Status.h" 26 #include "lldb/Utility/Stream.h" 27 28 #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" 29 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 30 #include <tuple> 31 32 using namespace lldb; 33 using namespace lldb_private; 34 using namespace lldb_private::formatters; 35 36 bool lldb_private::formatters::LibcxxOptionalSummaryProvider( 37 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 38 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 39 if (!valobj_sp) 40 return false; 41 42 // An optional either contains a value or not, the member __engaged_ is 43 // a bool flag, it is true if the optional has a value and false otherwise. 44 ValueObjectSP engaged_sp( 45 valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true)); 46 47 if (!engaged_sp) 48 return false; 49 50 llvm::StringRef engaged_as_cstring( 51 engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false"); 52 53 stream.Printf(" Has Value=%s ", engaged_as_cstring.data()); 54 55 return true; 56 } 57 58 bool lldb_private::formatters::LibcxxFunctionSummaryProvider( 59 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 60 61 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 62 63 if (!valobj_sp) 64 return false; 65 66 ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); 67 Process *process = exe_ctx.GetProcessPtr(); 68 69 if (process == nullptr) 70 return false; 71 72 CPPLanguageRuntime *cpp_runtime = CPPLanguageRuntime::Get(*process); 73 74 if (!cpp_runtime) 75 return false; 76 77 CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info = 78 cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp); 79 80 switch (callable_info.callable_case) { 81 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid: 82 stream.Printf(" __f_ = %" PRIu64, callable_info.member_f_pointer_value); 83 return false; 84 break; 85 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda: 86 stream.Printf( 87 " Lambda in File %s at Line %u", 88 callable_info.callable_line_entry.file.GetFilename().GetCString(), 89 callable_info.callable_line_entry.line); 90 break; 91 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject: 92 stream.Printf( 93 " Function in File %s at Line %u", 94 callable_info.callable_line_entry.file.GetFilename().GetCString(), 95 callable_info.callable_line_entry.line); 96 break; 97 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction: 98 stream.Printf(" Function = %s ", 99 callable_info.callable_symbol.GetName().GetCString()); 100 break; 101 } 102 103 return true; 104 } 105 106 bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( 107 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 108 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 109 if (!valobj_sp) 110 return false; 111 ValueObjectSP ptr_sp( 112 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); 113 ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath( 114 {ConstString("__cntrl_"), ConstString("__shared_owners_")})); 115 ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath( 116 {ConstString("__cntrl_"), ConstString("__shared_weak_owners_")})); 117 118 if (!ptr_sp) 119 return false; 120 121 if (ptr_sp->GetValueAsUnsigned(0) == 0) { 122 stream.Printf("nullptr"); 123 return true; 124 } else { 125 bool print_pointee = false; 126 Status error; 127 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 128 if (pointee_sp && error.Success()) { 129 if (pointee_sp->DumpPrintableRepresentation( 130 stream, ValueObject::eValueObjectRepresentationStyleSummary, 131 lldb::eFormatInvalid, 132 ValueObject::PrintableRepresentationSpecialCases::eDisable, 133 false)) 134 print_pointee = true; 135 } 136 if (!print_pointee) 137 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 138 } 139 140 if (count_sp) 141 stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0)); 142 143 if (weakcount_sp) 144 stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0)); 145 146 return true; 147 } 148 149 bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( 150 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 151 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 152 if (!valobj_sp) 153 return false; 154 155 ValueObjectSP ptr_sp( 156 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); 157 if (!ptr_sp) 158 return false; 159 160 ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); 161 if (!ptr_sp) 162 return false; 163 164 if (ptr_sp->GetValueAsUnsigned(0) == 0) { 165 stream.Printf("nullptr"); 166 return true; 167 } else { 168 bool print_pointee = false; 169 Status error; 170 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 171 if (pointee_sp && error.Success()) { 172 if (pointee_sp->DumpPrintableRepresentation( 173 stream, ValueObject::eValueObjectRepresentationStyleSummary, 174 lldb::eFormatInvalid, 175 ValueObject::PrintableRepresentationSpecialCases::eDisable, 176 false)) 177 print_pointee = true; 178 } 179 if (!print_pointee) 180 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 181 } 182 183 return true; 184 } 185 186 /* 187 (lldb) fr var ibeg --raw --ptr-depth 1 188 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, 189 std::__1::basic_string<char, std::__1::char_traits<char>, 190 std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, 191 std::__1::basic_string<char, std::__1::char_traits<char>, 192 std::__1::allocator<char> > >, void *> *, long> >) ibeg = { 193 __i_ = { 194 __ptr_ = 0x0000000100103870 { 195 std::__1::__tree_node_base<void *> = { 196 std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = { 197 __left_ = 0x0000000000000000 198 } 199 __right_ = 0x0000000000000000 200 __parent_ = 0x00000001001038b0 201 __is_black_ = true 202 } 203 __value_ = { 204 first = 0 205 second = { std::string } 206 */ 207 208 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 209 LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 210 : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { 211 if (valobj_sp) 212 Update(); 213 } 214 215 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { 216 m_pair_sp.reset(); 217 m_pair_ptr = nullptr; 218 219 ValueObjectSP valobj_sp = m_backend.GetSP(); 220 if (!valobj_sp) 221 return false; 222 223 TargetSP target_sp(valobj_sp->GetTargetSP()); 224 225 if (!target_sp) 226 return false; 227 228 if (!valobj_sp) 229 return false; 230 231 static ConstString g_i_("__i_"); 232 233 // this must be a ValueObject* because it is a child of the ValueObject we 234 // are producing children for it if were a ValueObjectSP, we would end up 235 // with a loop (iterator -> synthetic -> child -> parent == iterator) and 236 // that would in turn leak memory by never allowing the ValueObjects to die 237 // and free their memory 238 m_pair_ptr = valobj_sp 239 ->GetValueForExpressionPath( 240 ".__i_.__ptr_->__value_", nullptr, nullptr, 241 ValueObject::GetValueForExpressionPathOptions() 242 .DontCheckDotVsArrowSyntax() 243 .SetSyntheticChildrenTraversal( 244 ValueObject::GetValueForExpressionPathOptions:: 245 SyntheticChildrenTraversal::None), 246 nullptr) 247 .get(); 248 249 if (!m_pair_ptr) { 250 m_pair_ptr = valobj_sp 251 ->GetValueForExpressionPath( 252 ".__i_.__ptr_", nullptr, nullptr, 253 ValueObject::GetValueForExpressionPathOptions() 254 .DontCheckDotVsArrowSyntax() 255 .SetSyntheticChildrenTraversal( 256 ValueObject::GetValueForExpressionPathOptions:: 257 SyntheticChildrenTraversal::None), 258 nullptr) 259 .get(); 260 if (m_pair_ptr) { 261 auto __i_(valobj_sp->GetChildMemberWithName(g_i_, true)); 262 if (!__i_) { 263 m_pair_ptr = nullptr; 264 return false; 265 } 266 CompilerType pair_type( 267 __i_->GetCompilerType().GetTypeTemplateArgument(0)); 268 std::string name; 269 uint64_t bit_offset_ptr; 270 uint32_t bitfield_bit_size_ptr; 271 bool is_bitfield_ptr; 272 pair_type = pair_type.GetFieldAtIndex( 273 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); 274 if (!pair_type) { 275 m_pair_ptr = nullptr; 276 return false; 277 } 278 279 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); 280 m_pair_ptr = nullptr; 281 if (addr && addr != LLDB_INVALID_ADDRESS) { 282 TypeSystemClang *ast_ctx = 283 llvm::dyn_cast_or_null<TypeSystemClang>(pair_type.GetTypeSystem()); 284 if (!ast_ctx) 285 return false; 286 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( 287 ConstString(), 288 {{"ptr0", 289 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 290 {"ptr1", 291 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 292 {"ptr2", 293 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 294 {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, 295 {"payload", pair_type}}); 296 llvm::Optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); 297 if (!size) 298 return false; 299 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); 300 ProcessSP process_sp(target_sp->GetProcessSP()); 301 Status error; 302 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), 303 buffer_sp->GetByteSize(), error); 304 if (error.Fail()) 305 return false; 306 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), 307 process_sp->GetAddressByteSize()); 308 auto pair_sp = CreateValueObjectFromData( 309 "pair", extractor, valobj_sp->GetExecutionContextRef(), 310 tree_node_type); 311 if (pair_sp) 312 m_pair_sp = pair_sp->GetChildAtIndex(4, true); 313 } 314 } 315 } 316 317 return false; 318 } 319 320 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 321 CalculateNumChildren() { 322 return 2; 323 } 324 325 lldb::ValueObjectSP 326 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 327 size_t idx) { 328 if (m_pair_ptr) 329 return m_pair_ptr->GetChildAtIndex(idx, true); 330 if (m_pair_sp) 331 return m_pair_sp->GetChildAtIndex(idx, true); 332 return lldb::ValueObjectSP(); 333 } 334 335 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 336 MightHaveChildren() { 337 return true; 338 } 339 340 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 341 GetIndexOfChildWithName(ConstString name) { 342 if (name == "first") 343 return 0; 344 if (name == "second") 345 return 1; 346 return UINT32_MAX; 347 } 348 349 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 350 ~LibCxxMapIteratorSyntheticFrontEnd() { 351 // this will be deleted when its parent dies (since it's a child object) 352 // delete m_pair_ptr; 353 } 354 355 SyntheticChildrenFrontEnd * 356 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 357 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 358 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 359 : nullptr); 360 } 361 362 /* 363 (lldb) fr var ibeg --raw --ptr-depth 1 -T 364 (std::__1::__wrap_iter<int *>) ibeg = { 365 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { 366 (int) *__i = 1 367 } 368 } 369 */ 370 371 SyntheticChildrenFrontEnd * 372 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( 373 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 374 static ConstString g_item_name; 375 if (!g_item_name) 376 g_item_name.SetCString("__i"); 377 return (valobj_sp 378 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) 379 : nullptr); 380 } 381 382 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 383 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 384 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr) { 385 if (valobj_sp) 386 Update(); 387 } 388 389 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 390 CalculateNumChildren() { 391 return (m_cntrl ? 1 : 0); 392 } 393 394 lldb::ValueObjectSP 395 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( 396 size_t idx) { 397 if (!m_cntrl) 398 return lldb::ValueObjectSP(); 399 400 ValueObjectSP valobj_sp = m_backend.GetSP(); 401 if (!valobj_sp) 402 return lldb::ValueObjectSP(); 403 404 if (idx == 0) 405 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); 406 407 if (idx == 1) { 408 if (auto ptr_sp = 409 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)) { 410 Status status; 411 auto value_sp = ptr_sp->Dereference(status); 412 if (status.Success()) { 413 auto value_type_sp = 414 valobj_sp->GetCompilerType().GetTypeTemplateArgument(0); 415 return value_sp->Cast(value_type_sp); 416 } 417 } 418 } 419 420 return lldb::ValueObjectSP(); 421 } 422 423 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { 424 m_cntrl = nullptr; 425 426 ValueObjectSP valobj_sp = m_backend.GetSP(); 427 if (!valobj_sp) 428 return false; 429 430 TargetSP target_sp(valobj_sp->GetTargetSP()); 431 if (!target_sp) 432 return false; 433 434 lldb::ValueObjectSP cntrl_sp( 435 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); 436 437 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular 438 // dependency 439 return false; 440 } 441 442 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 443 MightHaveChildren() { 444 return true; 445 } 446 447 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 448 GetIndexOfChildWithName(ConstString name) { 449 if (name == "__ptr_") 450 return 0; 451 if (name == "$$dereference$$") 452 return 1; 453 return UINT32_MAX; 454 } 455 456 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 457 ~LibcxxSharedPtrSyntheticFrontEnd() = default; 458 459 SyntheticChildrenFrontEnd * 460 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( 461 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 462 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp) 463 : nullptr); 464 } 465 466 lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 467 LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 468 : SyntheticChildrenFrontEnd(*valobj_sp) { 469 if (valobj_sp) 470 Update(); 471 } 472 473 lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 474 ~LibcxxUniquePtrSyntheticFrontEnd() = default; 475 476 SyntheticChildrenFrontEnd * 477 lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator( 478 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 479 return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp) 480 : nullptr); 481 } 482 483 size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 484 CalculateNumChildren() { 485 return (m_value_ptr_sp ? 1 : 0); 486 } 487 488 lldb::ValueObjectSP 489 lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex( 490 size_t idx) { 491 if (!m_value_ptr_sp) 492 return lldb::ValueObjectSP(); 493 494 if (idx == 0) 495 return m_value_ptr_sp; 496 497 if (idx == 1) { 498 Status status; 499 auto value_sp = m_value_ptr_sp->Dereference(status); 500 if (status.Success()) { 501 return value_sp; 502 } 503 } 504 505 return lldb::ValueObjectSP(); 506 } 507 508 bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { 509 ValueObjectSP valobj_sp = m_backend.GetSP(); 510 if (!valobj_sp) 511 return false; 512 513 ValueObjectSP ptr_sp( 514 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); 515 if (!ptr_sp) 516 return false; 517 518 m_value_ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); 519 520 return false; 521 } 522 523 bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 524 MightHaveChildren() { 525 return true; 526 } 527 528 size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: 529 GetIndexOfChildWithName(ConstString name) { 530 if (name == "__value_") 531 return 0; 532 if (name == "$$dereference$$") 533 return 1; 534 return UINT32_MAX; 535 } 536 537 bool lldb_private::formatters::LibcxxContainerSummaryProvider( 538 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 539 if (valobj.IsPointerType()) { 540 uint64_t value = valobj.GetValueAsUnsigned(0); 541 if (!value) 542 return false; 543 stream.Printf("0x%016" PRIx64 " ", value); 544 } 545 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr, 546 nullptr, nullptr, &valobj, false, false); 547 } 548 549 /// The field layout in a libc++ string (cap, side, data or data, size, cap). 550 enum LibcxxStringLayoutMode { 551 eLibcxxStringLayoutModeCSD = 0, 552 eLibcxxStringLayoutModeDSC = 1, 553 eLibcxxStringLayoutModeInvalid = 0xffff 554 }; 555 556 /// Determine the size in bytes of \p valobj (a libc++ std::string object) and 557 /// extract its data payload. Return the size + payload pair. 558 // TODO: Support big-endian architectures. 559 static llvm::Optional<std::pair<uint64_t, ValueObjectSP>> 560 ExtractLibcxxStringInfo(ValueObject &valobj) { 561 ValueObjectSP dataval_sp(valobj.GetChildAtIndexPath({0, 0, 0, 0})); 562 if (!dataval_sp) 563 return {}; 564 if (!dataval_sp->GetError().Success()) 565 return {}; 566 567 ValueObjectSP layout_decider( 568 dataval_sp->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0}))); 569 570 // this child should exist 571 if (!layout_decider) 572 return {}; 573 574 ConstString g_data_name("__data_"); 575 ConstString g_size_name("__size_"); 576 bool short_mode = false; // this means the string is in short-mode and the 577 // data is stored inline 578 bool using_bitmasks = true; // Whether the class uses bitmasks for the mode 579 // flag (pre-D123580). 580 uint64_t size; 581 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) 582 ? eLibcxxStringLayoutModeDSC 583 : eLibcxxStringLayoutModeCSD; 584 uint64_t size_mode_value = 0; 585 586 ValueObjectSP short_sp(dataval_sp->GetChildAtIndex(1, true)); 587 if (!short_sp) 588 return {}; 589 590 ValueObjectSP short_fields_sp; 591 ValueObjectSP is_long = 592 short_sp->GetChildMemberWithName(ConstString("__is_long_"), true); 593 if (is_long) { 594 short_fields_sp = short_sp; 595 } else { 596 // After D128285, we need to access the `__is_long_` and `__size_` fields 597 // from a packed anonymous struct 598 short_fields_sp = short_sp->GetChildAtIndex(0, true); 599 is_long = short_sp->GetChildMemberWithName(ConstString("__is_long_"), true); 600 } 601 602 if (is_long) { 603 using_bitmasks = false; 604 short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0); 605 if (ValueObjectSP size_member = 606 dataval_sp->GetChildAtNamePath({ConstString("__s"), ConstString("__size_")})) 607 size = size_member->GetValueAsUnsigned(/*fail_value=*/0); 608 else 609 return {}; 610 } else if (layout == eLibcxxStringLayoutModeDSC) { 611 llvm::SmallVector<size_t, 3> size_mode_locations[] = { 612 {1, 2}, // Post-c3d0205ee771 layout. This was in use for only a brief 613 // period, so we can delete it if it becomes a burden. 614 {1, 1, 0}, 615 {1, 1, 1}, 616 }; 617 ValueObjectSP size_mode; 618 for (llvm::ArrayRef<size_t> loc : size_mode_locations) { 619 size_mode = dataval_sp->GetChildAtIndexPath(loc); 620 if (size_mode && size_mode->GetName() == g_size_name) 621 break; 622 } 623 624 if (!size_mode) 625 return {}; 626 627 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 628 short_mode = ((size_mode_value & 0x80) == 0); 629 } else { 630 ValueObjectSP size_mode(dataval_sp->GetChildAtIndexPath({1, 0, 0})); 631 if (!size_mode) 632 return {}; 633 634 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 635 short_mode = ((size_mode_value & 1) == 0); 636 } 637 638 if (short_mode) { 639 ValueObjectSP location_sp = 640 short_sp->GetChildMemberWithName(g_data_name, true); 641 if (using_bitmasks) 642 size = (layout == eLibcxxStringLayoutModeDSC) 643 ? size_mode_value 644 : ((size_mode_value >> 1) % 256); 645 646 // When the small-string optimization takes place, the data must fit in the 647 // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's 648 // likely that the string isn't initialized and we're reading garbage. 649 ExecutionContext exe_ctx(location_sp->GetExecutionContextRef()); 650 const llvm::Optional<uint64_t> max_bytes = 651 location_sp->GetCompilerType().GetByteSize( 652 exe_ctx.GetBestExecutionContextScope()); 653 if (!max_bytes || size > *max_bytes || !location_sp) 654 return {}; 655 656 return std::make_pair(size, location_sp); 657 } 658 659 ValueObjectSP l(dataval_sp->GetChildAtIndex(0, true)); 660 if (!l) 661 return {}; 662 663 // we can use the layout_decider object as the data pointer 664 ValueObjectSP location_sp = 665 l->GetChildMemberWithName(ConstString("__data_"), /*can_create=*/true); 666 ValueObjectSP size_vo = 667 l->GetChildMemberWithName(ConstString("__size_"), /*can_create=*/true); 668 ValueObjectSP capacity_vo = 669 l->GetChildMemberWithName(ConstString("__cap_"), /*can_create=*/true); 670 if (!capacity_vo) { 671 // After D128285, we need to access the `__cap_` field from a packed 672 // anonymous struct 673 if (ValueObjectSP packed_fields_sp = l->GetChildAtIndex(0, true)) { 674 ValueObjectSP capacity_vo = packed_fields_sp->GetChildMemberWithName( 675 ConstString("__cap_"), /*can_create=*/true); 676 } 677 } 678 if (!size_vo || !location_sp || !capacity_vo) 679 return {}; 680 size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); 681 uint64_t capacity = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); 682 if (!using_bitmasks && layout == eLibcxxStringLayoutModeCSD) 683 capacity *= 2; 684 if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET || 685 capacity < size) 686 return {}; 687 return std::make_pair(size, location_sp); 688 } 689 690 static bool 691 LibcxxWStringSummaryProvider(ValueObject &valobj, Stream &stream, 692 const TypeSummaryOptions &summary_options, 693 ValueObjectSP location_sp, size_t size) { 694 if (size == 0) { 695 stream.Printf("L\"\""); 696 return true; 697 } 698 if (!location_sp) 699 return false; 700 701 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 702 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 703 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 704 if (size > max_size) { 705 size = max_size; 706 options.SetIsTruncated(true); 707 } 708 } 709 710 DataExtractor extractor; 711 const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); 712 if (bytes_read < size) 713 return false; 714 715 // std::wstring::size() is measured in 'characters', not bytes 716 TypeSystemClang *ast_context = 717 ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP()); 718 if (!ast_context) 719 return false; 720 721 auto wchar_t_size = 722 ast_context->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr); 723 if (!wchar_t_size) 724 return false; 725 726 options.SetData(std::move(extractor)); 727 options.SetStream(&stream); 728 options.SetPrefixToken("L"); 729 options.SetQuote('"'); 730 options.SetSourceSize(size); 731 options.SetBinaryZeroIsTerminator(false); 732 733 switch (*wchar_t_size) { 734 case 1: 735 return StringPrinter::ReadBufferAndDumpToStream< 736 lldb_private::formatters::StringPrinter::StringElementType::UTF8>( 737 options); 738 break; 739 740 case 2: 741 return StringPrinter::ReadBufferAndDumpToStream< 742 lldb_private::formatters::StringPrinter::StringElementType::UTF16>( 743 options); 744 break; 745 746 case 4: 747 return StringPrinter::ReadBufferAndDumpToStream< 748 lldb_private::formatters::StringPrinter::StringElementType::UTF32>( 749 options); 750 } 751 return false; 752 } 753 754 bool lldb_private::formatters::LibcxxWStringSummaryProvider( 755 ValueObject &valobj, Stream &stream, 756 const TypeSummaryOptions &summary_options) { 757 auto string_info = ExtractLibcxxStringInfo(valobj); 758 if (!string_info) 759 return false; 760 uint64_t size; 761 ValueObjectSP location_sp; 762 std::tie(size, location_sp) = *string_info; 763 764 return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options, 765 location_sp, size); 766 } 767 768 template <StringPrinter::StringElementType element_type> 769 static bool 770 LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, 771 const TypeSummaryOptions &summary_options, 772 std::string prefix_token, ValueObjectSP location_sp, 773 uint64_t size) { 774 775 if (size == 0) { 776 stream.Printf("\"\""); 777 return true; 778 } 779 780 if (!location_sp) 781 return false; 782 783 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 784 785 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 786 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 787 if (size > max_size) { 788 size = max_size; 789 options.SetIsTruncated(true); 790 } 791 } 792 793 { 794 DataExtractor extractor; 795 const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); 796 if (bytes_read < size) 797 return false; 798 799 options.SetData(std::move(extractor)); 800 } 801 options.SetStream(&stream); 802 if (prefix_token.empty()) 803 options.SetPrefixToken(nullptr); 804 else 805 options.SetPrefixToken(prefix_token); 806 options.SetQuote('"'); 807 options.SetSourceSize(size); 808 options.SetBinaryZeroIsTerminator(false); 809 return StringPrinter::ReadBufferAndDumpToStream<element_type>(options); 810 } 811 812 template <StringPrinter::StringElementType element_type> 813 static bool 814 LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, 815 const TypeSummaryOptions &summary_options, 816 std::string prefix_token) { 817 auto string_info = ExtractLibcxxStringInfo(valobj); 818 if (!string_info) 819 return false; 820 uint64_t size; 821 ValueObjectSP location_sp; 822 std::tie(size, location_sp) = *string_info; 823 824 return LibcxxStringSummaryProvider<element_type>( 825 valobj, stream, summary_options, prefix_token, location_sp, size); 826 } 827 template <StringPrinter::StringElementType element_type> 828 static bool formatStringImpl(ValueObject &valobj, Stream &stream, 829 const TypeSummaryOptions &summary_options, 830 std::string prefix_token) { 831 StreamString scratch_stream; 832 const bool success = LibcxxStringSummaryProvider<element_type>( 833 valobj, scratch_stream, summary_options, prefix_token); 834 if (success) 835 stream << scratch_stream.GetData(); 836 else 837 stream << "Summary Unavailable"; 838 return true; 839 } 840 841 bool lldb_private::formatters::LibcxxStringSummaryProviderASCII( 842 ValueObject &valobj, Stream &stream, 843 const TypeSummaryOptions &summary_options) { 844 return formatStringImpl<StringPrinter::StringElementType::ASCII>( 845 valobj, stream, summary_options, ""); 846 } 847 848 bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16( 849 ValueObject &valobj, Stream &stream, 850 const TypeSummaryOptions &summary_options) { 851 return formatStringImpl<StringPrinter::StringElementType::UTF16>( 852 valobj, stream, summary_options, "u"); 853 } 854 855 bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32( 856 ValueObject &valobj, Stream &stream, 857 const TypeSummaryOptions &summary_options) { 858 return formatStringImpl<StringPrinter::StringElementType::UTF32>( 859 valobj, stream, summary_options, "U"); 860 } 861 862 static std::tuple<bool, ValueObjectSP, size_t> 863 LibcxxExtractStringViewData(ValueObject& valobj) { 864 ConstString g_data_name("__data"); 865 ConstString g_size_name("__size"); 866 auto dataobj = valobj.GetChildMemberWithName(g_data_name, true); 867 auto sizeobj = valobj.GetChildMemberWithName(g_size_name, true); 868 869 if (!dataobj || !sizeobj) 870 return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {}); 871 872 if (!dataobj->GetError().Success() || !sizeobj->GetError().Success()) 873 return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {}); 874 875 bool success{false}; 876 uint64_t size = sizeobj->GetValueAsUnsigned(0, &success); 877 if (!success) 878 return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {}); 879 880 return std::make_tuple(true,dataobj,size); 881 } 882 883 template <StringPrinter::StringElementType element_type> 884 static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, 885 const TypeSummaryOptions &summary_options, 886 std::string prefix_token) { 887 888 bool success; 889 ValueObjectSP dataobj; 890 size_t size; 891 std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj); 892 893 if (!success) { 894 stream << "Summary Unavailable"; 895 return true; 896 } 897 898 return LibcxxStringSummaryProvider<element_type>( 899 valobj, stream, summary_options, prefix_token, dataobj, size); 900 } 901 902 bool lldb_private::formatters::LibcxxStringViewSummaryProviderASCII( 903 ValueObject &valobj, Stream &stream, 904 const TypeSummaryOptions &summary_options) { 905 return formatStringViewImpl<StringPrinter::StringElementType::ASCII>( 906 valobj, stream, summary_options, ""); 907 } 908 909 bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16( 910 ValueObject &valobj, Stream &stream, 911 const TypeSummaryOptions &summary_options) { 912 return formatStringViewImpl<StringPrinter::StringElementType::UTF16>( 913 valobj, stream, summary_options, "u"); 914 } 915 916 bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32( 917 ValueObject &valobj, Stream &stream, 918 const TypeSummaryOptions &summary_options) { 919 return formatStringViewImpl<StringPrinter::StringElementType::UTF32>( 920 valobj, stream, summary_options, "U"); 921 } 922 923 bool lldb_private::formatters::LibcxxWStringViewSummaryProvider( 924 ValueObject &valobj, Stream &stream, 925 const TypeSummaryOptions &summary_options) { 926 927 bool success; 928 ValueObjectSP dataobj; 929 size_t size; 930 std::tie( success, dataobj, size ) = LibcxxExtractStringViewData(valobj); 931 932 if (!success) { 933 stream << "Summary Unavailable"; 934 return true; 935 } 936 937 938 return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options, 939 dataobj, size); 940 } 941