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