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