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/Error.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 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.GetString(), 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, 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 294 ->GetValueForExpressionPath( 295 ".__i_.__ptr_", nullptr, nullptr, 296 ValueObject::GetValueForExpressionPathOptions() 297 .DontCheckDotVsArrowSyntax() 298 .SetSyntheticChildrenTraversal( 299 ValueObject::GetValueForExpressionPathOptions:: 300 SyntheticChildrenTraversal::None), 301 nullptr) 302 .get(); 303 if (m_pair_ptr) { 304 auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true)); 305 lldb::TemplateArgumentKind kind; 306 if (!__i_) { 307 m_pair_ptr = nullptr; 308 return false; 309 } 310 CompilerType pair_type(__i_->GetCompilerType().GetTemplateArgument(0, kind)); 311 std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr; 312 pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); 313 if (!pair_type) { 314 m_pair_ptr = nullptr; 315 return false; 316 } 317 318 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); 319 m_pair_ptr = nullptr; 320 if (addr && addr!=LLDB_INVALID_ADDRESS) { 321 ClangASTContext *ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); 322 if (!ast_ctx) 323 return false; 324 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), { 325 {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 326 {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 327 {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 328 {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, 329 {"payload",pair_type} 330 }); 331 DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0)); 332 ProcessSP process_sp(target_sp->GetProcessSP()); 333 Error error; 334 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error); 335 if (error.Fail()) 336 return false; 337 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 338 auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type); 339 if (pair_sp) 340 m_pair_sp = pair_sp->GetChildAtIndex(4,true); 341 } 342 } 343 } 344 345 return false; 346 } 347 348 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 349 CalculateNumChildren() { 350 return 2; 351 } 352 353 lldb::ValueObjectSP 354 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 355 size_t idx) { 356 if (m_pair_ptr) 357 return m_pair_ptr->GetChildAtIndex(idx, true); 358 if (m_pair_sp) 359 return m_pair_sp->GetChildAtIndex(idx, true); 360 return lldb::ValueObjectSP(); 361 } 362 363 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 364 MightHaveChildren() { 365 return true; 366 } 367 368 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 369 GetIndexOfChildWithName(const ConstString &name) { 370 if (name == ConstString("first")) 371 return 0; 372 if (name == ConstString("second")) 373 return 1; 374 return UINT32_MAX; 375 } 376 377 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 378 ~LibCxxMapIteratorSyntheticFrontEnd() { 379 // this will be deleted when its parent dies (since it's a child object) 380 // delete m_pair_ptr; 381 } 382 383 SyntheticChildrenFrontEnd * 384 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 385 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 386 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 387 : nullptr); 388 } 389 390 /* 391 (lldb) fr var ibeg --raw --ptr-depth 1 -T 392 (std::__1::__wrap_iter<int *>) ibeg = { 393 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { 394 (int) *__i = 1 395 } 396 } 397 */ 398 399 SyntheticChildrenFrontEnd * 400 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( 401 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 402 static ConstString g_item_name; 403 if (!g_item_name) 404 g_item_name.SetCString("__i"); 405 return (valobj_sp 406 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) 407 : nullptr); 408 } 409 410 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 411 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 412 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(), 413 m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) { 414 if (valobj_sp) 415 Update(); 416 } 417 418 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 419 CalculateNumChildren() { 420 return (m_cntrl ? 1 : 0); 421 } 422 423 lldb::ValueObjectSP 424 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( 425 size_t idx) { 426 if (!m_cntrl) 427 return lldb::ValueObjectSP(); 428 429 ValueObjectSP valobj_sp = m_backend.GetSP(); 430 if (!valobj_sp) 431 return lldb::ValueObjectSP(); 432 433 if (idx == 0) 434 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); 435 436 if (idx > 2) 437 return lldb::ValueObjectSP(); 438 439 if (idx == 1) { 440 if (!m_count_sp) { 441 ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName( 442 ConstString("__shared_owners_"), true)); 443 if (!shared_owners_sp) 444 return lldb::ValueObjectSP(); 445 uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0); 446 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 447 m_count_sp = CreateValueObjectFromData( 448 "count", data, valobj_sp->GetExecutionContextRef(), 449 shared_owners_sp->GetCompilerType()); 450 } 451 return m_count_sp; 452 } else /* if (idx == 2) */ 453 { 454 if (!m_weak_count_sp) { 455 ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName( 456 ConstString("__shared_weak_owners_"), true)); 457 if (!shared_weak_owners_sp) 458 return lldb::ValueObjectSP(); 459 uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0); 460 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 461 m_weak_count_sp = CreateValueObjectFromData( 462 "count", data, valobj_sp->GetExecutionContextRef(), 463 shared_weak_owners_sp->GetCompilerType()); 464 } 465 return m_weak_count_sp; 466 } 467 } 468 469 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { 470 m_count_sp.reset(); 471 m_weak_count_sp.reset(); 472 m_cntrl = nullptr; 473 474 ValueObjectSP valobj_sp = m_backend.GetSP(); 475 if (!valobj_sp) 476 return false; 477 478 TargetSP target_sp(valobj_sp->GetTargetSP()); 479 if (!target_sp) 480 return false; 481 482 m_byte_order = target_sp->GetArchitecture().GetByteOrder(); 483 m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize(); 484 485 lldb::ValueObjectSP cntrl_sp( 486 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); 487 488 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular 489 // dependency 490 return false; 491 } 492 493 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 494 MightHaveChildren() { 495 return true; 496 } 497 498 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 499 GetIndexOfChildWithName(const ConstString &name) { 500 if (name == ConstString("__ptr_")) 501 return 0; 502 if (name == ConstString("count")) 503 return 1; 504 if (name == ConstString("weak_count")) 505 return 2; 506 return UINT32_MAX; 507 } 508 509 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 510 ~LibcxxSharedPtrSyntheticFrontEnd() = default; 511 512 SyntheticChildrenFrontEnd * 513 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( 514 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 515 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp) 516 : nullptr); 517 } 518 519 bool lldb_private::formatters::LibcxxContainerSummaryProvider( 520 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 521 if (valobj.IsPointerType()) { 522 uint64_t value = valobj.GetValueAsUnsigned(0); 523 if (!value) 524 return false; 525 stream.Printf("0x%016" PRIx64 " ", value); 526 } 527 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr, 528 nullptr, nullptr, &valobj, false, false); 529 } 530 531 // the field layout in a libc++ string (cap, side, data or data, size, cap) 532 enum LibcxxStringLayoutMode { 533 eLibcxxStringLayoutModeCSD = 0, 534 eLibcxxStringLayoutModeDSC = 1, 535 eLibcxxStringLayoutModeInvalid = 0xffff 536 }; 537 538 // this function abstracts away the layout and mode details of a libc++ string 539 // and returns the address of the data and the size ready for callers to consume 540 static bool ExtractLibcxxStringInfo(ValueObject &valobj, 541 ValueObjectSP &location_sp, 542 uint64_t &size) { 543 ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); 544 if (!D) 545 return false; 546 547 ValueObjectSP layout_decider(D->GetChildAtIndexPath({0, 0})); 548 549 // this child should exist 550 if (!layout_decider) 551 return false; 552 553 ConstString g_data_name("__data_"); 554 ConstString g_size_name("__size_"); 555 bool short_mode = false; // this means the string is in short-mode and the 556 // data is stored inline 557 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) 558 ? eLibcxxStringLayoutModeDSC 559 : eLibcxxStringLayoutModeCSD; 560 uint64_t size_mode_value = 0; 561 562 if (layout == eLibcxxStringLayoutModeDSC) { 563 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); 564 if (!size_mode) 565 return false; 566 567 if (size_mode->GetName() != g_size_name) { 568 // we are hitting the padding structure, move along 569 size_mode = D->GetChildAtIndexPath({1, 1, 1}); 570 if (!size_mode) 571 return false; 572 } 573 574 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 575 short_mode = ((size_mode_value & 0x80) == 0); 576 } else { 577 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); 578 if (!size_mode) 579 return false; 580 581 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 582 short_mode = ((size_mode_value & 1) == 0); 583 } 584 585 if (short_mode) { 586 ValueObjectSP s(D->GetChildAtIndex(1, true)); 587 if (!s) 588 return false; 589 location_sp = s->GetChildAtIndex( 590 (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); 591 size = (layout == eLibcxxStringLayoutModeDSC) 592 ? size_mode_value 593 : ((size_mode_value >> 1) % 256); 594 return (location_sp.get() != nullptr); 595 } else { 596 ValueObjectSP l(D->GetChildAtIndex(0, true)); 597 if (!l) 598 return false; 599 // we can use the layout_decider object as the data pointer 600 location_sp = (layout == eLibcxxStringLayoutModeDSC) 601 ? layout_decider 602 : l->GetChildAtIndex(2, true); 603 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 604 if (!size_vo || !location_sp) 605 return false; 606 size = size_vo->GetValueAsUnsigned(0); 607 return true; 608 } 609 } 610 611 bool lldb_private::formatters::LibcxxWStringSummaryProvider( 612 ValueObject &valobj, Stream &stream, 613 const TypeSummaryOptions &summary_options) { 614 uint64_t size = 0; 615 ValueObjectSP location_sp; 616 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 617 return false; 618 if (size == 0) { 619 stream.Printf("L\"\""); 620 return true; 621 } 622 if (!location_sp) 623 return false; 624 625 DataExtractor extractor; 626 627 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 628 629 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 630 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 631 if (size > max_size) { 632 size = max_size; 633 options.SetIsTruncated(true); 634 } 635 } 636 location_sp->GetPointeeData(extractor, 0, size); 637 638 // std::wstring::size() is measured in 'characters', not bytes 639 auto wchar_t_size = valobj.GetTargetSP() 640 ->GetScratchClangASTContext() 641 ->GetBasicType(lldb::eBasicTypeWChar) 642 .GetByteSize(nullptr); 643 644 options.SetData(extractor); 645 options.SetStream(&stream); 646 options.SetPrefixToken("L"); 647 options.SetQuote('"'); 648 options.SetSourceSize(size); 649 options.SetBinaryZeroIsTerminator(false); 650 651 switch (wchar_t_size) { 652 case 1: 653 StringPrinter::ReadBufferAndDumpToStream< 654 lldb_private::formatters::StringPrinter::StringElementType::UTF8>( 655 options); 656 break; 657 658 case 2: 659 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 660 lldb_private::formatters::StringPrinter::StringElementType::UTF16>( 661 options); 662 break; 663 664 case 4: 665 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 666 lldb_private::formatters::StringPrinter::StringElementType::UTF32>( 667 options); 668 break; 669 670 default: 671 stream.Printf("size for wchar_t is not valid"); 672 return true; 673 } 674 675 return true; 676 } 677 678 bool lldb_private::formatters::LibcxxStringSummaryProvider( 679 ValueObject &valobj, Stream &stream, 680 const TypeSummaryOptions &summary_options) { 681 uint64_t size = 0; 682 ValueObjectSP location_sp; 683 684 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 685 return false; 686 687 if (size == 0) { 688 stream.Printf("\"\""); 689 return true; 690 } 691 692 if (!location_sp) 693 return false; 694 695 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 696 697 DataExtractor extractor; 698 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 699 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 700 if (size > max_size) { 701 size = max_size; 702 options.SetIsTruncated(true); 703 } 704 } 705 location_sp->GetPointeeData(extractor, 0, size); 706 707 options.SetData(extractor); 708 options.SetStream(&stream); 709 options.SetPrefixToken(nullptr); 710 options.SetQuote('"'); 711 options.SetSourceSize(size); 712 options.SetBinaryZeroIsTerminator(false); 713 StringPrinter::ReadBufferAndDumpToStream< 714 StringPrinter::StringElementType::ASCII>(options); 715 716 return true; 717 } 718 719 class LibcxxFunctionFrontEnd : public SyntheticValueProviderFrontEnd { 720 public: 721 LibcxxFunctionFrontEnd(ValueObject &backend) 722 : SyntheticValueProviderFrontEnd(backend) {} 723 724 lldb::ValueObjectSP GetSyntheticValue() override { 725 static ConstString g___f_("__f_"); 726 return m_backend.GetChildMemberWithName(g___f_, true); 727 } 728 }; 729 730 SyntheticChildrenFrontEnd * 731 lldb_private::formatters::LibcxxFunctionFrontEndCreator( 732 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 733 if (valobj_sp) 734 return new LibcxxFunctionFrontEnd(*valobj_sp); 735 return nullptr; 736 } 737