1 //===-- LibCxx.cpp ----------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "LibCxx.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/Debugger.h" 17 #include "lldb/Core/FormatEntity.h" 18 #include "lldb/Core/ValueObject.h" 19 #include "lldb/Core/ValueObjectConstResult.h" 20 #include "lldb/DataFormatters/FormattersHelpers.h" 21 #include "lldb/DataFormatters/StringPrinter.h" 22 #include "lldb/DataFormatters/TypeSummary.h" 23 #include "lldb/DataFormatters/VectorIterator.h" 24 #include "lldb/Symbol/ClangASTContext.h" 25 #include "lldb/Target/ProcessStructReader.h" 26 #include "lldb/Target/Target.h" 27 #include "lldb/Utility/DataBufferHeap.h" 28 #include "lldb/Utility/Endian.h" 29 #include "lldb/Utility/Status.h" 30 #include "lldb/Utility/Stream.h" 31 32 using namespace lldb; 33 using namespace lldb_private; 34 using namespace lldb_private::formatters; 35 36 bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( 37 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 38 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 39 if (!valobj_sp) 40 return false; 41 ValueObjectSP ptr_sp( 42 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); 43 ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath( 44 {ConstString("__cntrl_"), ConstString("__shared_owners_")})); 45 ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath( 46 {ConstString("__cntrl_"), ConstString("__shared_weak_owners_")})); 47 48 if (!ptr_sp) 49 return false; 50 51 if (ptr_sp->GetValueAsUnsigned(0) == 0) { 52 stream.Printf("nullptr"); 53 return true; 54 } else { 55 bool print_pointee = false; 56 Status error; 57 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 58 if (pointee_sp && error.Success()) { 59 if (pointee_sp->DumpPrintableRepresentation( 60 stream, ValueObject::eValueObjectRepresentationStyleSummary, 61 lldb::eFormatInvalid, 62 ValueObject::PrintableRepresentationSpecialCases::eDisable, 63 false)) 64 print_pointee = true; 65 } 66 if (!print_pointee) 67 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 68 } 69 70 if (count_sp) 71 stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0)); 72 73 if (weakcount_sp) 74 stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0)); 75 76 return true; 77 } 78 79 /* 80 (lldb) fr var ibeg --raw --ptr-depth 1 81 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, 82 std::__1::basic_string<char, std::__1::char_traits<char>, 83 std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, 84 std::__1::basic_string<char, std::__1::char_traits<char>, 85 std::__1::allocator<char> > >, void *> *, long> >) ibeg = { 86 __i_ = { 87 __ptr_ = 0x0000000100103870 { 88 std::__1::__tree_node_base<void *> = { 89 std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = { 90 __left_ = 0x0000000000000000 91 } 92 __right_ = 0x0000000000000000 93 __parent_ = 0x00000001001038b0 94 __is_black_ = true 95 } 96 __value_ = { 97 first = 0 98 second = { std::string } 99 */ 100 101 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 102 LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 103 : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { 104 if (valobj_sp) 105 Update(); 106 } 107 108 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { 109 m_pair_sp.reset(); 110 m_pair_ptr = nullptr; 111 112 ValueObjectSP valobj_sp = m_backend.GetSP(); 113 if (!valobj_sp) 114 return false; 115 116 TargetSP target_sp(valobj_sp->GetTargetSP()); 117 118 if (!target_sp) 119 return false; 120 121 if (!valobj_sp) 122 return false; 123 124 static ConstString g___i_("__i_"); 125 126 // this must be a ValueObject* because it is a child of the ValueObject we are 127 // producing children for 128 // it if were a ValueObjectSP, we would end up with a loop (iterator -> 129 // synthetic -> child -> parent == iterator) 130 // and that would in turn leak memory by never allowing the ValueObjects to 131 // die and free their memory 132 m_pair_ptr = valobj_sp 133 ->GetValueForExpressionPath( 134 ".__i_.__ptr_->__value_", nullptr, nullptr, 135 ValueObject::GetValueForExpressionPathOptions() 136 .DontCheckDotVsArrowSyntax() 137 .SetSyntheticChildrenTraversal( 138 ValueObject::GetValueForExpressionPathOptions:: 139 SyntheticChildrenTraversal::None), 140 nullptr) 141 .get(); 142 143 if (!m_pair_ptr) { 144 m_pair_ptr = valobj_sp 145 ->GetValueForExpressionPath( 146 ".__i_.__ptr_", nullptr, nullptr, 147 ValueObject::GetValueForExpressionPathOptions() 148 .DontCheckDotVsArrowSyntax() 149 .SetSyntheticChildrenTraversal( 150 ValueObject::GetValueForExpressionPathOptions:: 151 SyntheticChildrenTraversal::None), 152 nullptr) 153 .get(); 154 if (m_pair_ptr) { 155 auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true)); 156 if (!__i_) { 157 m_pair_ptr = nullptr; 158 return false; 159 } 160 CompilerType pair_type(__i_->GetCompilerType().GetTypeTemplateArgument(0)); 161 std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr; 162 pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); 163 if (!pair_type) { 164 m_pair_ptr = nullptr; 165 return false; 166 } 167 168 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); 169 m_pair_ptr = nullptr; 170 if (addr && addr!=LLDB_INVALID_ADDRESS) { 171 ClangASTContext *ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); 172 if (!ast_ctx) 173 return false; 174 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), { 175 {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 176 {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 177 {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 178 {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, 179 {"payload",pair_type} 180 }); 181 DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0)); 182 ProcessSP process_sp(target_sp->GetProcessSP()); 183 Status error; 184 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error); 185 if (error.Fail()) 186 return false; 187 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 188 auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type); 189 if (pair_sp) 190 m_pair_sp = pair_sp->GetChildAtIndex(4,true); 191 } 192 } 193 } 194 195 return false; 196 } 197 198 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 199 CalculateNumChildren() { 200 return 2; 201 } 202 203 lldb::ValueObjectSP 204 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 205 size_t idx) { 206 if (m_pair_ptr) 207 return m_pair_ptr->GetChildAtIndex(idx, true); 208 if (m_pair_sp) 209 return m_pair_sp->GetChildAtIndex(idx, true); 210 return lldb::ValueObjectSP(); 211 } 212 213 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 214 MightHaveChildren() { 215 return true; 216 } 217 218 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 219 GetIndexOfChildWithName(const ConstString &name) { 220 if (name == ConstString("first")) 221 return 0; 222 if (name == ConstString("second")) 223 return 1; 224 return UINT32_MAX; 225 } 226 227 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 228 ~LibCxxMapIteratorSyntheticFrontEnd() { 229 // this will be deleted when its parent dies (since it's a child object) 230 // delete m_pair_ptr; 231 } 232 233 SyntheticChildrenFrontEnd * 234 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 235 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 236 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 237 : nullptr); 238 } 239 240 /* 241 (lldb) fr var ibeg --raw --ptr-depth 1 -T 242 (std::__1::__wrap_iter<int *>) ibeg = { 243 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { 244 (int) *__i = 1 245 } 246 } 247 */ 248 249 SyntheticChildrenFrontEnd * 250 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( 251 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 252 static ConstString g_item_name; 253 if (!g_item_name) 254 g_item_name.SetCString("__i"); 255 return (valobj_sp 256 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) 257 : nullptr); 258 } 259 260 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 261 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 262 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(), 263 m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) { 264 if (valobj_sp) 265 Update(); 266 } 267 268 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 269 CalculateNumChildren() { 270 return (m_cntrl ? 1 : 0); 271 } 272 273 lldb::ValueObjectSP 274 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( 275 size_t idx) { 276 if (!m_cntrl) 277 return lldb::ValueObjectSP(); 278 279 ValueObjectSP valobj_sp = m_backend.GetSP(); 280 if (!valobj_sp) 281 return lldb::ValueObjectSP(); 282 283 if (idx == 0) 284 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); 285 286 if (idx > 2) 287 return lldb::ValueObjectSP(); 288 289 if (idx == 1) { 290 if (!m_count_sp) { 291 ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName( 292 ConstString("__shared_owners_"), true)); 293 if (!shared_owners_sp) 294 return lldb::ValueObjectSP(); 295 uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0); 296 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 297 m_count_sp = CreateValueObjectFromData( 298 "count", data, valobj_sp->GetExecutionContextRef(), 299 shared_owners_sp->GetCompilerType()); 300 } 301 return m_count_sp; 302 } else /* if (idx == 2) */ 303 { 304 if (!m_weak_count_sp) { 305 ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName( 306 ConstString("__shared_weak_owners_"), true)); 307 if (!shared_weak_owners_sp) 308 return lldb::ValueObjectSP(); 309 uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0); 310 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 311 m_weak_count_sp = CreateValueObjectFromData( 312 "count", data, valobj_sp->GetExecutionContextRef(), 313 shared_weak_owners_sp->GetCompilerType()); 314 } 315 return m_weak_count_sp; 316 } 317 } 318 319 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { 320 m_count_sp.reset(); 321 m_weak_count_sp.reset(); 322 m_cntrl = nullptr; 323 324 ValueObjectSP valobj_sp = m_backend.GetSP(); 325 if (!valobj_sp) 326 return false; 327 328 TargetSP target_sp(valobj_sp->GetTargetSP()); 329 if (!target_sp) 330 return false; 331 332 m_byte_order = target_sp->GetArchitecture().GetByteOrder(); 333 m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize(); 334 335 lldb::ValueObjectSP cntrl_sp( 336 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); 337 338 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular 339 // dependency 340 return false; 341 } 342 343 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 344 MightHaveChildren() { 345 return true; 346 } 347 348 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 349 GetIndexOfChildWithName(const ConstString &name) { 350 if (name == ConstString("__ptr_")) 351 return 0; 352 if (name == ConstString("count")) 353 return 1; 354 if (name == ConstString("weak_count")) 355 return 2; 356 return UINT32_MAX; 357 } 358 359 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 360 ~LibcxxSharedPtrSyntheticFrontEnd() = default; 361 362 SyntheticChildrenFrontEnd * 363 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( 364 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 365 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp) 366 : nullptr); 367 } 368 369 bool lldb_private::formatters::LibcxxContainerSummaryProvider( 370 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 371 if (valobj.IsPointerType()) { 372 uint64_t value = valobj.GetValueAsUnsigned(0); 373 if (!value) 374 return false; 375 stream.Printf("0x%016" PRIx64 " ", value); 376 } 377 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr, 378 nullptr, nullptr, &valobj, false, false); 379 } 380 381 // the field layout in a libc++ string (cap, side, data or data, size, cap) 382 enum LibcxxStringLayoutMode { 383 eLibcxxStringLayoutModeCSD = 0, 384 eLibcxxStringLayoutModeDSC = 1, 385 eLibcxxStringLayoutModeInvalid = 0xffff 386 }; 387 388 // this function abstracts away the layout and mode details of a libc++ string 389 // and returns the address of the data and the size ready for callers to consume 390 static bool ExtractLibcxxStringInfo(ValueObject &valobj, 391 ValueObjectSP &location_sp, 392 uint64_t &size) { 393 ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); 394 if (!D) 395 return false; 396 397 ValueObjectSP layout_decider( 398 D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0}))); 399 400 // this child should exist 401 if (!layout_decider) 402 return false; 403 404 ConstString g_data_name("__data_"); 405 ConstString g_size_name("__size_"); 406 bool short_mode = false; // this means the string is in short-mode and the 407 // data is stored inline 408 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) 409 ? eLibcxxStringLayoutModeDSC 410 : eLibcxxStringLayoutModeCSD; 411 uint64_t size_mode_value = 0; 412 413 if (layout == eLibcxxStringLayoutModeDSC) { 414 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); 415 if (!size_mode) 416 return false; 417 418 if (size_mode->GetName() != g_size_name) { 419 // we are hitting the padding structure, move along 420 size_mode = D->GetChildAtIndexPath({1, 1, 1}); 421 if (!size_mode) 422 return false; 423 } 424 425 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 426 short_mode = ((size_mode_value & 0x80) == 0); 427 } else { 428 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); 429 if (!size_mode) 430 return false; 431 432 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 433 short_mode = ((size_mode_value & 1) == 0); 434 } 435 436 if (short_mode) { 437 ValueObjectSP s(D->GetChildAtIndex(1, true)); 438 if (!s) 439 return false; 440 location_sp = s->GetChildAtIndex( 441 (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); 442 size = (layout == eLibcxxStringLayoutModeDSC) 443 ? size_mode_value 444 : ((size_mode_value >> 1) % 256); 445 return (location_sp.get() != nullptr); 446 } else { 447 ValueObjectSP l(D->GetChildAtIndex(0, true)); 448 if (!l) 449 return false; 450 // we can use the layout_decider object as the data pointer 451 location_sp = (layout == eLibcxxStringLayoutModeDSC) 452 ? layout_decider 453 : l->GetChildAtIndex(2, true); 454 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 455 if (!size_vo || !location_sp) 456 return false; 457 size = size_vo->GetValueAsUnsigned(0); 458 return true; 459 } 460 } 461 462 bool lldb_private::formatters::LibcxxWStringSummaryProvider( 463 ValueObject &valobj, Stream &stream, 464 const TypeSummaryOptions &summary_options) { 465 uint64_t size = 0; 466 ValueObjectSP location_sp; 467 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 468 return false; 469 if (size == 0) { 470 stream.Printf("L\"\""); 471 return true; 472 } 473 if (!location_sp) 474 return false; 475 476 DataExtractor extractor; 477 478 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 479 480 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 481 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 482 if (size > max_size) { 483 size = max_size; 484 options.SetIsTruncated(true); 485 } 486 } 487 location_sp->GetPointeeData(extractor, 0, size); 488 489 // std::wstring::size() is measured in 'characters', not bytes 490 auto wchar_t_size = valobj.GetTargetSP() 491 ->GetScratchClangASTContext() 492 ->GetBasicType(lldb::eBasicTypeWChar) 493 .GetByteSize(nullptr); 494 495 options.SetData(extractor); 496 options.SetStream(&stream); 497 options.SetPrefixToken("L"); 498 options.SetQuote('"'); 499 options.SetSourceSize(size); 500 options.SetBinaryZeroIsTerminator(false); 501 502 switch (wchar_t_size) { 503 case 1: 504 StringPrinter::ReadBufferAndDumpToStream< 505 lldb_private::formatters::StringPrinter::StringElementType::UTF8>( 506 options); 507 break; 508 509 case 2: 510 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 511 lldb_private::formatters::StringPrinter::StringElementType::UTF16>( 512 options); 513 break; 514 515 case 4: 516 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 517 lldb_private::formatters::StringPrinter::StringElementType::UTF32>( 518 options); 519 break; 520 521 default: 522 stream.Printf("size for wchar_t is not valid"); 523 return true; 524 } 525 526 return true; 527 } 528 529 bool lldb_private::formatters::LibcxxStringSummaryProvider( 530 ValueObject &valobj, Stream &stream, 531 const TypeSummaryOptions &summary_options) { 532 uint64_t size = 0; 533 ValueObjectSP location_sp; 534 535 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 536 return false; 537 538 if (size == 0) { 539 stream.Printf("\"\""); 540 return true; 541 } 542 543 if (!location_sp) 544 return false; 545 546 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 547 548 DataExtractor extractor; 549 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 550 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 551 if (size > max_size) { 552 size = max_size; 553 options.SetIsTruncated(true); 554 } 555 } 556 location_sp->GetPointeeData(extractor, 0, size); 557 558 options.SetData(extractor); 559 options.SetStream(&stream); 560 options.SetPrefixToken(nullptr); 561 options.SetQuote('"'); 562 options.SetSourceSize(size); 563 options.SetBinaryZeroIsTerminator(false); 564 StringPrinter::ReadBufferAndDumpToStream< 565 StringPrinter::StringElementType::ASCII>(options); 566 567 return true; 568 } 569 570 class LibcxxFunctionFrontEnd : public SyntheticValueProviderFrontEnd { 571 public: 572 LibcxxFunctionFrontEnd(ValueObject &backend) 573 : SyntheticValueProviderFrontEnd(backend) {} 574 575 lldb::ValueObjectSP GetSyntheticValue() override { 576 static ConstString g___f_("__f_"); 577 return m_backend.GetChildMemberWithName(g___f_, true); 578 } 579 }; 580 581 SyntheticChildrenFrontEnd * 582 lldb_private::formatters::LibcxxFunctionFrontEndCreator( 583 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 584 if (valobj_sp) 585 return new LibcxxFunctionFrontEnd(*valobj_sp); 586 return nullptr; 587 } 588