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 127 // are producing children for it if were a ValueObjectSP, we would end up 128 // with a loop (iterator -> synthetic -> child -> parent == iterator) and 129 // that would in turn leak memory by never allowing the ValueObjects to die 130 // and free their memory 131 m_pair_ptr = valobj_sp 132 ->GetValueForExpressionPath( 133 ".__i_.__ptr_->__value_", nullptr, nullptr, 134 ValueObject::GetValueForExpressionPathOptions() 135 .DontCheckDotVsArrowSyntax() 136 .SetSyntheticChildrenTraversal( 137 ValueObject::GetValueForExpressionPathOptions:: 138 SyntheticChildrenTraversal::None), 139 nullptr) 140 .get(); 141 142 if (!m_pair_ptr) { 143 m_pair_ptr = valobj_sp 144 ->GetValueForExpressionPath( 145 ".__i_.__ptr_", nullptr, nullptr, 146 ValueObject::GetValueForExpressionPathOptions() 147 .DontCheckDotVsArrowSyntax() 148 .SetSyntheticChildrenTraversal( 149 ValueObject::GetValueForExpressionPathOptions:: 150 SyntheticChildrenTraversal::None), 151 nullptr) 152 .get(); 153 if (m_pair_ptr) { 154 auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true)); 155 if (!__i_) { 156 m_pair_ptr = nullptr; 157 return false; 158 } 159 CompilerType pair_type(__i_->GetCompilerType().GetTypeTemplateArgument(0)); 160 std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr; 161 pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); 162 if (!pair_type) { 163 m_pair_ptr = nullptr; 164 return false; 165 } 166 167 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); 168 m_pair_ptr = nullptr; 169 if (addr && addr!=LLDB_INVALID_ADDRESS) { 170 ClangASTContext *ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); 171 if (!ast_ctx) 172 return false; 173 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), { 174 {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 175 {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 176 {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 177 {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, 178 {"payload",pair_type} 179 }); 180 DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0)); 181 ProcessSP process_sp(target_sp->GetProcessSP()); 182 Status error; 183 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error); 184 if (error.Fail()) 185 return false; 186 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 187 auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type); 188 if (pair_sp) 189 m_pair_sp = pair_sp->GetChildAtIndex(4,true); 190 } 191 } 192 } 193 194 return false; 195 } 196 197 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 198 CalculateNumChildren() { 199 return 2; 200 } 201 202 lldb::ValueObjectSP 203 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 204 size_t idx) { 205 if (m_pair_ptr) 206 return m_pair_ptr->GetChildAtIndex(idx, true); 207 if (m_pair_sp) 208 return m_pair_sp->GetChildAtIndex(idx, true); 209 return lldb::ValueObjectSP(); 210 } 211 212 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 213 MightHaveChildren() { 214 return true; 215 } 216 217 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 218 GetIndexOfChildWithName(const ConstString &name) { 219 if (name == ConstString("first")) 220 return 0; 221 if (name == ConstString("second")) 222 return 1; 223 return UINT32_MAX; 224 } 225 226 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 227 ~LibCxxMapIteratorSyntheticFrontEnd() { 228 // this will be deleted when its parent dies (since it's a child object) 229 // delete m_pair_ptr; 230 } 231 232 SyntheticChildrenFrontEnd * 233 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 234 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 235 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 236 : nullptr); 237 } 238 239 /* 240 (lldb) fr var ibeg --raw --ptr-depth 1 -T 241 (std::__1::__wrap_iter<int *>) ibeg = { 242 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { 243 (int) *__i = 1 244 } 245 } 246 */ 247 248 SyntheticChildrenFrontEnd * 249 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( 250 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 251 static ConstString g_item_name; 252 if (!g_item_name) 253 g_item_name.SetCString("__i"); 254 return (valobj_sp 255 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) 256 : nullptr); 257 } 258 259 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 260 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 261 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(), 262 m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) { 263 if (valobj_sp) 264 Update(); 265 } 266 267 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 268 CalculateNumChildren() { 269 return (m_cntrl ? 1 : 0); 270 } 271 272 lldb::ValueObjectSP 273 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( 274 size_t idx) { 275 if (!m_cntrl) 276 return lldb::ValueObjectSP(); 277 278 ValueObjectSP valobj_sp = m_backend.GetSP(); 279 if (!valobj_sp) 280 return lldb::ValueObjectSP(); 281 282 if (idx == 0) 283 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); 284 285 if (idx > 2) 286 return lldb::ValueObjectSP(); 287 288 if (idx == 1) { 289 if (!m_count_sp) { 290 ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName( 291 ConstString("__shared_owners_"), true)); 292 if (!shared_owners_sp) 293 return lldb::ValueObjectSP(); 294 uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0); 295 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 296 m_count_sp = CreateValueObjectFromData( 297 "count", data, valobj_sp->GetExecutionContextRef(), 298 shared_owners_sp->GetCompilerType()); 299 } 300 return m_count_sp; 301 } else /* if (idx == 2) */ 302 { 303 if (!m_weak_count_sp) { 304 ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName( 305 ConstString("__shared_weak_owners_"), true)); 306 if (!shared_weak_owners_sp) 307 return lldb::ValueObjectSP(); 308 uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0); 309 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 310 m_weak_count_sp = CreateValueObjectFromData( 311 "count", data, valobj_sp->GetExecutionContextRef(), 312 shared_weak_owners_sp->GetCompilerType()); 313 } 314 return m_weak_count_sp; 315 } 316 } 317 318 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { 319 m_count_sp.reset(); 320 m_weak_count_sp.reset(); 321 m_cntrl = nullptr; 322 323 ValueObjectSP valobj_sp = m_backend.GetSP(); 324 if (!valobj_sp) 325 return false; 326 327 TargetSP target_sp(valobj_sp->GetTargetSP()); 328 if (!target_sp) 329 return false; 330 331 m_byte_order = target_sp->GetArchitecture().GetByteOrder(); 332 m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize(); 333 334 lldb::ValueObjectSP cntrl_sp( 335 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); 336 337 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular 338 // dependency 339 return false; 340 } 341 342 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 343 MightHaveChildren() { 344 return true; 345 } 346 347 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 348 GetIndexOfChildWithName(const ConstString &name) { 349 if (name == ConstString("__ptr_")) 350 return 0; 351 if (name == ConstString("count")) 352 return 1; 353 if (name == ConstString("weak_count")) 354 return 2; 355 return UINT32_MAX; 356 } 357 358 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 359 ~LibcxxSharedPtrSyntheticFrontEnd() = default; 360 361 SyntheticChildrenFrontEnd * 362 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( 363 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 364 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp) 365 : nullptr); 366 } 367 368 bool lldb_private::formatters::LibcxxContainerSummaryProvider( 369 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 370 if (valobj.IsPointerType()) { 371 uint64_t value = valobj.GetValueAsUnsigned(0); 372 if (!value) 373 return false; 374 stream.Printf("0x%016" PRIx64 " ", value); 375 } 376 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr, 377 nullptr, nullptr, &valobj, false, false); 378 } 379 380 // the field layout in a libc++ string (cap, side, data or data, size, cap) 381 enum LibcxxStringLayoutMode { 382 eLibcxxStringLayoutModeCSD = 0, 383 eLibcxxStringLayoutModeDSC = 1, 384 eLibcxxStringLayoutModeInvalid = 0xffff 385 }; 386 387 // this function abstracts away the layout and mode details of a libc++ string 388 // and returns the address of the data and the size ready for callers to 389 // 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