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