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