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