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