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