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 #include "llvm/ADT/ScopeExit.h" 16 // Project includes 17 #include "lldb/Core/Debugger.h" 18 #include "lldb/Core/FormatEntity.h" 19 #include "lldb/Core/ValueObject.h" 20 #include "lldb/Core/ValueObjectConstResult.h" 21 #include "lldb/DataFormatters/FormattersHelpers.h" 22 #include "lldb/DataFormatters/StringPrinter.h" 23 #include "lldb/DataFormatters/TypeSummary.h" 24 #include "lldb/DataFormatters/VectorIterator.h" 25 #include "lldb/Symbol/ClangASTContext.h" 26 #include "lldb/Target/ProcessStructReader.h" 27 #include "lldb/Target/SectionLoadList.h" 28 #include "lldb/Target/Target.h" 29 #include "lldb/Utility/DataBufferHeap.h" 30 #include "lldb/Utility/Endian.h" 31 #include "lldb/Utility/Status.h" 32 #include "lldb/Utility/Stream.h" 33 34 using namespace lldb; 35 using namespace lldb_private; 36 using namespace lldb_private::formatters; 37 38 bool lldb_private::formatters::LibcxxOptionalSummaryProvider( 39 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 40 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 41 if (!valobj_sp) 42 return false; 43 44 // An optional either contains a value or not, the member __engaged_ is 45 // a bool flag, it is true if the optional has a value and false otherwise. 46 ValueObjectSP engaged_sp( 47 valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true)); 48 49 if (!engaged_sp) 50 return false; 51 52 llvm::StringRef engaged_as_cstring( 53 engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false"); 54 55 stream.Printf(" Has Value=%s ", engaged_as_cstring.data()); 56 57 return true; 58 } 59 60 bool lldb_private::formatters::LibcxxFunctionSummaryProvider( 61 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 62 63 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 64 65 if (!valobj_sp) 66 return false; 67 68 // Member __f_ has type __base*, the contents of which will hold: 69 // 1) a vtable entry which may hold type information needed to discover the 70 // lambda being called 71 // 2) possibly hold a pointer to the callable object 72 // e.g. 73 // 74 // (lldb) frame var -R f_display 75 // (std::__1::function<void (int)>) f_display = { 76 // __buf_ = { 77 // … 78 // } 79 // __f_ = 0x00007ffeefbffa00 80 // } 81 // (lldb) memory read -fA 0x00007ffeefbffa00 82 // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ... 83 // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ... 84 // 85 // We will be handling five cases below, std::function is wrapping: 86 // 87 // 1) a lambda we know at compile time. We will obtain the name of the lambda 88 // from the first template pameter from __func's vtable. We will look up 89 // the lambda's operator()() and obtain the line table entry. 90 // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method 91 // will be stored after the vtable. We will obtain the lambdas name from 92 // this entry and lookup operator()() and obtain the line table entry. 93 // 3) a callable object via operator()(). We will obtain the name of the 94 // object from the first template parameter from __func's vtable. We will 95 // look up the objectc operator()() and obtain the line table entry. 96 // 4) a member function. A pointer to the function will stored after the 97 // we will obtain the name from this pointer. 98 // 5) a free function. A pointer to the function will stored after the vtable 99 // we will obtain the name from this pointer. 100 ValueObjectSP member__f_( 101 valobj_sp->GetChildMemberWithName(ConstString("__f_"), true)); 102 lldb::addr_t member__f_pointer_value = member__f_->GetValueAsUnsigned(0); 103 104 ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); 105 Process *process = exe_ctx.GetProcessPtr(); 106 107 if (process == nullptr) 108 return false; 109 110 uint32_t address_size = process->GetAddressByteSize(); 111 Status status; 112 113 // First item pointed to by __f_ should be the pointer to the vtable for 114 // a __base object. 115 lldb::addr_t vtable_address = 116 process->ReadPointerFromMemory(member__f_pointer_value, status); 117 118 if (status.Fail()) 119 return false; 120 121 bool found_wrapped_function = false; 122 123 // Using scoped exit so we can use early return and still execute the default 124 // action in case we don't find the wrapper function. Otherwise we can't use 125 // early exit without duplicating code. 126 auto default_print_on_exit = llvm::make_scope_exit( 127 [&found_wrapped_function, &stream, &member__f_pointer_value]() { 128 if (!found_wrapped_function) 129 stream.Printf(" __f_ = %" PRIu64, member__f_pointer_value); 130 }); 131 132 lldb::addr_t address_after_vtable = member__f_pointer_value + address_size; 133 // As commened above we may not have a function pointer but if we do we will 134 // need it. 135 lldb::addr_t possible_function_address = 136 process->ReadPointerFromMemory(address_after_vtable, status); 137 138 if (status.Fail()) 139 return false; 140 141 Target &target = process->GetTarget(); 142 143 if (target.GetSectionLoadList().IsEmpty()) 144 return false; 145 146 Address vtable_addr_resolved; 147 SymbolContext sc; 148 Symbol *symbol; 149 150 if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address, 151 vtable_addr_resolved)) 152 return false; 153 154 target.GetImages().ResolveSymbolContextForAddress( 155 vtable_addr_resolved, eSymbolContextEverything, sc); 156 symbol = sc.symbol; 157 158 if (symbol == NULL) 159 return false; 160 161 llvm::StringRef vtable_name(symbol->GetName().GetCString()); 162 bool found_expected_start_string = 163 vtable_name.startswith("vtable for std::__1::__function::__func<"); 164 165 if (!found_expected_start_string) 166 return false; 167 168 // Given case 1 or 3 we have a vtable name, we are want to extract the first 169 // template parameter 170 // 171 // ... __func<main::$_0, std::__1::allocator<main::$_0> ... 172 // ^^^^^^^^^ 173 // 174 // We do this by find the first < and , and extracting in between. 175 // 176 // This covers the case of the lambda known at compile time. 177 // 178 size_t first_open_angle_bracket = vtable_name.find('<') + 1; 179 size_t first_comma = vtable_name.find_first_of(','); 180 181 llvm::StringRef first_template_parameter = 182 vtable_name.slice(first_open_angle_bracket, first_comma); 183 184 Address function_address_resolved; 185 186 // Setup for cases 2, 4 and 5 we have a pointer to a function after the 187 // vtable. We will use a process of elimination to drop through each case 188 // and obtain the data we need. 189 if (target.GetSectionLoadList().ResolveLoadAddress( 190 possible_function_address, function_address_resolved)) { 191 target.GetImages().ResolveSymbolContextForAddress( 192 function_address_resolved, eSymbolContextEverything, sc); 193 symbol = sc.symbol; 194 } 195 196 auto get_name = [&first_template_parameter, &symbol]() { 197 // Given case 1: 198 // 199 // main::$_0 200 // 201 // we want to append ::operator()() 202 if (first_template_parameter.contains("$_")) 203 return llvm::Regex::escape(first_template_parameter.str()) + 204 R"(::operator\(\)\(.*\))"; 205 206 if (symbol != NULL && 207 symbol->GetName().GetStringRef().contains("__invoke")) { 208 209 llvm::StringRef symbol_name = symbol->GetName().GetStringRef(); 210 size_t pos2 = symbol_name.find_last_of(':'); 211 212 // Given case 2: 213 // 214 // main::$_1::__invoke(...) 215 // 216 // We want to slice off __invoke(...) and append operator()() 217 std::string lambda_operator = 218 llvm::Regex::escape(symbol_name.slice(0, pos2 + 1).str()) + 219 R"(operator\(\)\(.*\))"; 220 221 return lambda_operator; 222 } 223 224 // Case 3 225 return first_template_parameter.str() + R"(::operator\(\)\(.*\))"; 226 ; 227 }; 228 229 std::string func_to_match = get_name(); 230 231 SymbolContextList scl; 232 233 target.GetImages().FindFunctions(RegularExpression{func_to_match}, true, true, 234 true, scl); 235 236 // Case 1,2 or 3 237 if (scl.GetSize() >= 1) { 238 SymbolContext sc2 = scl[0]; 239 240 AddressRange range; 241 sc2.GetAddressRange(eSymbolContextEverything, 0, false, range); 242 243 Address address = range.GetBaseAddress(); 244 245 Address addr; 246 if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target), 247 addr)) { 248 LineEntry line_entry; 249 addr.CalculateSymbolContextLineEntry(line_entry); 250 251 found_wrapped_function = true; 252 if (first_template_parameter.contains("$_") || 253 (symbol != NULL && 254 symbol->GetName().GetStringRef().contains("__invoke"))) { 255 // Case 1 and 2 256 stream.Printf(" Lambda in File %s at Line %u", 257 line_entry.file.GetFilename().GetCString(), 258 line_entry.line); 259 } else { 260 // Case 3 261 stream.Printf(" Function in File %s at Line %u", 262 line_entry.file.GetFilename().GetCString(), 263 line_entry.line); 264 } 265 266 return true; 267 } 268 } 269 270 // Case 4 or 5 271 if (!symbol->GetName().GetStringRef().startswith("vtable for")) { 272 found_wrapped_function = true; 273 stream.Printf(" Function = %s ", symbol->GetName().GetCString()); 274 return true; 275 } 276 277 return false; 278 } 279 280 bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( 281 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 282 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 283 if (!valobj_sp) 284 return false; 285 ValueObjectSP ptr_sp( 286 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); 287 ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath( 288 {ConstString("__cntrl_"), ConstString("__shared_owners_")})); 289 ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath( 290 {ConstString("__cntrl_"), ConstString("__shared_weak_owners_")})); 291 292 if (!ptr_sp) 293 return false; 294 295 if (ptr_sp->GetValueAsUnsigned(0) == 0) { 296 stream.Printf("nullptr"); 297 return true; 298 } else { 299 bool print_pointee = false; 300 Status error; 301 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 302 if (pointee_sp && error.Success()) { 303 if (pointee_sp->DumpPrintableRepresentation( 304 stream, ValueObject::eValueObjectRepresentationStyleSummary, 305 lldb::eFormatInvalid, 306 ValueObject::PrintableRepresentationSpecialCases::eDisable, 307 false)) 308 print_pointee = true; 309 } 310 if (!print_pointee) 311 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 312 } 313 314 if (count_sp) 315 stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0)); 316 317 if (weakcount_sp) 318 stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0)); 319 320 return true; 321 } 322 323 /* 324 (lldb) fr var ibeg --raw --ptr-depth 1 325 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, 326 std::__1::basic_string<char, std::__1::char_traits<char>, 327 std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, 328 std::__1::basic_string<char, std::__1::char_traits<char>, 329 std::__1::allocator<char> > >, void *> *, long> >) ibeg = { 330 __i_ = { 331 __ptr_ = 0x0000000100103870 { 332 std::__1::__tree_node_base<void *> = { 333 std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = { 334 __left_ = 0x0000000000000000 335 } 336 __right_ = 0x0000000000000000 337 __parent_ = 0x00000001001038b0 338 __is_black_ = true 339 } 340 __value_ = { 341 first = 0 342 second = { std::string } 343 */ 344 345 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 346 LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 347 : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { 348 if (valobj_sp) 349 Update(); 350 } 351 352 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { 353 m_pair_sp.reset(); 354 m_pair_ptr = nullptr; 355 356 ValueObjectSP valobj_sp = m_backend.GetSP(); 357 if (!valobj_sp) 358 return false; 359 360 TargetSP target_sp(valobj_sp->GetTargetSP()); 361 362 if (!target_sp) 363 return false; 364 365 if (!valobj_sp) 366 return false; 367 368 static ConstString g___i_("__i_"); 369 370 // this must be a ValueObject* because it is a child of the ValueObject we 371 // are producing children for it if were a ValueObjectSP, we would end up 372 // with a loop (iterator -> synthetic -> child -> parent == iterator) and 373 // that would in turn leak memory by never allowing the ValueObjects to die 374 // and free their memory 375 m_pair_ptr = valobj_sp 376 ->GetValueForExpressionPath( 377 ".__i_.__ptr_->__value_", nullptr, nullptr, 378 ValueObject::GetValueForExpressionPathOptions() 379 .DontCheckDotVsArrowSyntax() 380 .SetSyntheticChildrenTraversal( 381 ValueObject::GetValueForExpressionPathOptions:: 382 SyntheticChildrenTraversal::None), 383 nullptr) 384 .get(); 385 386 if (!m_pair_ptr) { 387 m_pair_ptr = valobj_sp 388 ->GetValueForExpressionPath( 389 ".__i_.__ptr_", nullptr, nullptr, 390 ValueObject::GetValueForExpressionPathOptions() 391 .DontCheckDotVsArrowSyntax() 392 .SetSyntheticChildrenTraversal( 393 ValueObject::GetValueForExpressionPathOptions:: 394 SyntheticChildrenTraversal::None), 395 nullptr) 396 .get(); 397 if (m_pair_ptr) { 398 auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true)); 399 if (!__i_) { 400 m_pair_ptr = nullptr; 401 return false; 402 } 403 CompilerType pair_type(__i_->GetCompilerType().GetTypeTemplateArgument(0)); 404 std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr; 405 pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); 406 if (!pair_type) { 407 m_pair_ptr = nullptr; 408 return false; 409 } 410 411 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); 412 m_pair_ptr = nullptr; 413 if (addr && addr!=LLDB_INVALID_ADDRESS) { 414 ClangASTContext *ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); 415 if (!ast_ctx) 416 return false; 417 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), { 418 {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 419 {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 420 {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 421 {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, 422 {"payload",pair_type} 423 }); 424 DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0)); 425 ProcessSP process_sp(target_sp->GetProcessSP()); 426 Status error; 427 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error); 428 if (error.Fail()) 429 return false; 430 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 431 auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type); 432 if (pair_sp) 433 m_pair_sp = pair_sp->GetChildAtIndex(4,true); 434 } 435 } 436 } 437 438 return false; 439 } 440 441 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 442 CalculateNumChildren() { 443 return 2; 444 } 445 446 lldb::ValueObjectSP 447 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 448 size_t idx) { 449 if (m_pair_ptr) 450 return m_pair_ptr->GetChildAtIndex(idx, true); 451 if (m_pair_sp) 452 return m_pair_sp->GetChildAtIndex(idx, true); 453 return lldb::ValueObjectSP(); 454 } 455 456 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 457 MightHaveChildren() { 458 return true; 459 } 460 461 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 462 GetIndexOfChildWithName(const ConstString &name) { 463 if (name == ConstString("first")) 464 return 0; 465 if (name == ConstString("second")) 466 return 1; 467 return UINT32_MAX; 468 } 469 470 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 471 ~LibCxxMapIteratorSyntheticFrontEnd() { 472 // this will be deleted when its parent dies (since it's a child object) 473 // delete m_pair_ptr; 474 } 475 476 SyntheticChildrenFrontEnd * 477 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 478 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 479 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 480 : nullptr); 481 } 482 483 /* 484 (lldb) fr var ibeg --raw --ptr-depth 1 -T 485 (std::__1::__wrap_iter<int *>) ibeg = { 486 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { 487 (int) *__i = 1 488 } 489 } 490 */ 491 492 SyntheticChildrenFrontEnd * 493 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( 494 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 495 static ConstString g_item_name; 496 if (!g_item_name) 497 g_item_name.SetCString("__i"); 498 return (valobj_sp 499 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) 500 : nullptr); 501 } 502 503 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 504 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 505 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(), 506 m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) { 507 if (valobj_sp) 508 Update(); 509 } 510 511 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 512 CalculateNumChildren() { 513 return (m_cntrl ? 1 : 0); 514 } 515 516 lldb::ValueObjectSP 517 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( 518 size_t idx) { 519 if (!m_cntrl) 520 return lldb::ValueObjectSP(); 521 522 ValueObjectSP valobj_sp = m_backend.GetSP(); 523 if (!valobj_sp) 524 return lldb::ValueObjectSP(); 525 526 if (idx == 0) 527 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); 528 529 if (idx > 2) 530 return lldb::ValueObjectSP(); 531 532 if (idx == 1) { 533 if (!m_count_sp) { 534 ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName( 535 ConstString("__shared_owners_"), true)); 536 if (!shared_owners_sp) 537 return lldb::ValueObjectSP(); 538 uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0); 539 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 540 m_count_sp = CreateValueObjectFromData( 541 "count", data, valobj_sp->GetExecutionContextRef(), 542 shared_owners_sp->GetCompilerType()); 543 } 544 return m_count_sp; 545 } else /* if (idx == 2) */ 546 { 547 if (!m_weak_count_sp) { 548 ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName( 549 ConstString("__shared_weak_owners_"), true)); 550 if (!shared_weak_owners_sp) 551 return lldb::ValueObjectSP(); 552 uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0); 553 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 554 m_weak_count_sp = CreateValueObjectFromData( 555 "count", data, valobj_sp->GetExecutionContextRef(), 556 shared_weak_owners_sp->GetCompilerType()); 557 } 558 return m_weak_count_sp; 559 } 560 } 561 562 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { 563 m_count_sp.reset(); 564 m_weak_count_sp.reset(); 565 m_cntrl = nullptr; 566 567 ValueObjectSP valobj_sp = m_backend.GetSP(); 568 if (!valobj_sp) 569 return false; 570 571 TargetSP target_sp(valobj_sp->GetTargetSP()); 572 if (!target_sp) 573 return false; 574 575 m_byte_order = target_sp->GetArchitecture().GetByteOrder(); 576 m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize(); 577 578 lldb::ValueObjectSP cntrl_sp( 579 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); 580 581 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular 582 // dependency 583 return false; 584 } 585 586 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 587 MightHaveChildren() { 588 return true; 589 } 590 591 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 592 GetIndexOfChildWithName(const ConstString &name) { 593 if (name == ConstString("__ptr_")) 594 return 0; 595 if (name == ConstString("count")) 596 return 1; 597 if (name == ConstString("weak_count")) 598 return 2; 599 return UINT32_MAX; 600 } 601 602 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 603 ~LibcxxSharedPtrSyntheticFrontEnd() = default; 604 605 SyntheticChildrenFrontEnd * 606 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( 607 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 608 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp) 609 : nullptr); 610 } 611 612 bool lldb_private::formatters::LibcxxContainerSummaryProvider( 613 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 614 if (valobj.IsPointerType()) { 615 uint64_t value = valobj.GetValueAsUnsigned(0); 616 if (!value) 617 return false; 618 stream.Printf("0x%016" PRIx64 " ", value); 619 } 620 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr, 621 nullptr, nullptr, &valobj, false, false); 622 } 623 624 // the field layout in a libc++ string (cap, side, data or data, size, cap) 625 enum LibcxxStringLayoutMode { 626 eLibcxxStringLayoutModeCSD = 0, 627 eLibcxxStringLayoutModeDSC = 1, 628 eLibcxxStringLayoutModeInvalid = 0xffff 629 }; 630 631 // this function abstracts away the layout and mode details of a libc++ string 632 // and returns the address of the data and the size ready for callers to 633 // consume 634 static bool ExtractLibcxxStringInfo(ValueObject &valobj, 635 ValueObjectSP &location_sp, 636 uint64_t &size) { 637 ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); 638 if (!D) 639 return false; 640 641 ValueObjectSP layout_decider( 642 D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0}))); 643 644 // this child should exist 645 if (!layout_decider) 646 return false; 647 648 ConstString g_data_name("__data_"); 649 ConstString g_size_name("__size_"); 650 bool short_mode = false; // this means the string is in short-mode and the 651 // data is stored inline 652 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) 653 ? eLibcxxStringLayoutModeDSC 654 : eLibcxxStringLayoutModeCSD; 655 uint64_t size_mode_value = 0; 656 657 if (layout == eLibcxxStringLayoutModeDSC) { 658 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); 659 if (!size_mode) 660 return false; 661 662 if (size_mode->GetName() != g_size_name) { 663 // we are hitting the padding structure, move along 664 size_mode = D->GetChildAtIndexPath({1, 1, 1}); 665 if (!size_mode) 666 return false; 667 } 668 669 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 670 short_mode = ((size_mode_value & 0x80) == 0); 671 } else { 672 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); 673 if (!size_mode) 674 return false; 675 676 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 677 short_mode = ((size_mode_value & 1) == 0); 678 } 679 680 if (short_mode) { 681 ValueObjectSP s(D->GetChildAtIndex(1, true)); 682 if (!s) 683 return false; 684 location_sp = s->GetChildAtIndex( 685 (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); 686 size = (layout == eLibcxxStringLayoutModeDSC) 687 ? size_mode_value 688 : ((size_mode_value >> 1) % 256); 689 return (location_sp.get() != nullptr); 690 } else { 691 ValueObjectSP l(D->GetChildAtIndex(0, true)); 692 if (!l) 693 return false; 694 // we can use the layout_decider object as the data pointer 695 location_sp = (layout == eLibcxxStringLayoutModeDSC) 696 ? layout_decider 697 : l->GetChildAtIndex(2, true); 698 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 699 if (!size_vo || !location_sp) 700 return false; 701 size = size_vo->GetValueAsUnsigned(0); 702 return true; 703 } 704 } 705 706 bool lldb_private::formatters::LibcxxWStringSummaryProvider( 707 ValueObject &valobj, Stream &stream, 708 const TypeSummaryOptions &summary_options) { 709 uint64_t size = 0; 710 ValueObjectSP location_sp; 711 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 712 return false; 713 if (size == 0) { 714 stream.Printf("L\"\""); 715 return true; 716 } 717 if (!location_sp) 718 return false; 719 720 DataExtractor extractor; 721 722 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 723 724 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 725 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 726 if (size > max_size) { 727 size = max_size; 728 options.SetIsTruncated(true); 729 } 730 } 731 location_sp->GetPointeeData(extractor, 0, size); 732 733 // std::wstring::size() is measured in 'characters', not bytes 734 auto wchar_t_size = valobj.GetTargetSP() 735 ->GetScratchClangASTContext() 736 ->GetBasicType(lldb::eBasicTypeWChar) 737 .GetByteSize(nullptr); 738 739 options.SetData(extractor); 740 options.SetStream(&stream); 741 options.SetPrefixToken("L"); 742 options.SetQuote('"'); 743 options.SetSourceSize(size); 744 options.SetBinaryZeroIsTerminator(false); 745 746 switch (wchar_t_size) { 747 case 1: 748 StringPrinter::ReadBufferAndDumpToStream< 749 lldb_private::formatters::StringPrinter::StringElementType::UTF8>( 750 options); 751 break; 752 753 case 2: 754 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 755 lldb_private::formatters::StringPrinter::StringElementType::UTF16>( 756 options); 757 break; 758 759 case 4: 760 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 761 lldb_private::formatters::StringPrinter::StringElementType::UTF32>( 762 options); 763 break; 764 765 default: 766 stream.Printf("size for wchar_t is not valid"); 767 return true; 768 } 769 770 return true; 771 } 772 773 bool lldb_private::formatters::LibcxxStringSummaryProvider( 774 ValueObject &valobj, Stream &stream, 775 const TypeSummaryOptions &summary_options) { 776 uint64_t size = 0; 777 ValueObjectSP location_sp; 778 779 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 780 return false; 781 782 if (size == 0) { 783 stream.Printf("\"\""); 784 return true; 785 } 786 787 if (!location_sp) 788 return false; 789 790 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 791 792 DataExtractor extractor; 793 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 794 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 795 if (size > max_size) { 796 size = max_size; 797 options.SetIsTruncated(true); 798 } 799 } 800 location_sp->GetPointeeData(extractor, 0, size); 801 802 options.SetData(extractor); 803 options.SetStream(&stream); 804 options.SetPrefixToken(nullptr); 805 options.SetQuote('"'); 806 options.SetSourceSize(size); 807 options.SetBinaryZeroIsTerminator(false); 808 StringPrinter::ReadBufferAndDumpToStream< 809 StringPrinter::StringElementType::ASCII>(options); 810 811 return true; 812 } 813