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/Status.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::LibcxxOptionalSummaryProvider( 37 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 38 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 39 if (!valobj_sp) 40 return false; 41 42 // An optional either contains a value or not, the member __engaged_ is 43 // a bool flag, it is true if the optional has a value and false otherwise. 44 ValueObjectSP engaged_sp( 45 valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true)); 46 47 if (!engaged_sp) 48 return false; 49 50 llvm::StringRef engaged_as_cstring( 51 engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false"); 52 53 stream.Printf(" Has Value=%s ", engaged_as_cstring.data()); 54 55 return true; 56 } 57 58 bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( 59 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 60 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 61 if (!valobj_sp) 62 return false; 63 ValueObjectSP ptr_sp( 64 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); 65 ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath( 66 {ConstString("__cntrl_"), ConstString("__shared_owners_")})); 67 ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath( 68 {ConstString("__cntrl_"), ConstString("__shared_weak_owners_")})); 69 70 if (!ptr_sp) 71 return false; 72 73 if (ptr_sp->GetValueAsUnsigned(0) == 0) { 74 stream.Printf("nullptr"); 75 return true; 76 } else { 77 bool print_pointee = false; 78 Status error; 79 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 80 if (pointee_sp && error.Success()) { 81 if (pointee_sp->DumpPrintableRepresentation( 82 stream, ValueObject::eValueObjectRepresentationStyleSummary, 83 lldb::eFormatInvalid, 84 ValueObject::PrintableRepresentationSpecialCases::eDisable, 85 false)) 86 print_pointee = true; 87 } 88 if (!print_pointee) 89 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 90 } 91 92 if (count_sp) 93 stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0)); 94 95 if (weakcount_sp) 96 stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0)); 97 98 return true; 99 } 100 101 /* 102 (lldb) fr var ibeg --raw --ptr-depth 1 103 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, 104 std::__1::basic_string<char, std::__1::char_traits<char>, 105 std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, 106 std::__1::basic_string<char, std::__1::char_traits<char>, 107 std::__1::allocator<char> > >, void *> *, long> >) ibeg = { 108 __i_ = { 109 __ptr_ = 0x0000000100103870 { 110 std::__1::__tree_node_base<void *> = { 111 std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = { 112 __left_ = 0x0000000000000000 113 } 114 __right_ = 0x0000000000000000 115 __parent_ = 0x00000001001038b0 116 __is_black_ = true 117 } 118 __value_ = { 119 first = 0 120 second = { std::string } 121 */ 122 123 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 124 LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 125 : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { 126 if (valobj_sp) 127 Update(); 128 } 129 130 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { 131 m_pair_sp.reset(); 132 m_pair_ptr = nullptr; 133 134 ValueObjectSP valobj_sp = m_backend.GetSP(); 135 if (!valobj_sp) 136 return false; 137 138 TargetSP target_sp(valobj_sp->GetTargetSP()); 139 140 if (!target_sp) 141 return false; 142 143 if (!valobj_sp) 144 return false; 145 146 static ConstString g___i_("__i_"); 147 148 // this must be a ValueObject* because it is a child of the ValueObject we 149 // are producing children for it if were a ValueObjectSP, we would end up 150 // with a loop (iterator -> synthetic -> child -> parent == iterator) and 151 // that would in turn leak memory by never allowing the ValueObjects to die 152 // and free their memory 153 m_pair_ptr = valobj_sp 154 ->GetValueForExpressionPath( 155 ".__i_.__ptr_->__value_", nullptr, nullptr, 156 ValueObject::GetValueForExpressionPathOptions() 157 .DontCheckDotVsArrowSyntax() 158 .SetSyntheticChildrenTraversal( 159 ValueObject::GetValueForExpressionPathOptions:: 160 SyntheticChildrenTraversal::None), 161 nullptr) 162 .get(); 163 164 if (!m_pair_ptr) { 165 m_pair_ptr = valobj_sp 166 ->GetValueForExpressionPath( 167 ".__i_.__ptr_", nullptr, nullptr, 168 ValueObject::GetValueForExpressionPathOptions() 169 .DontCheckDotVsArrowSyntax() 170 .SetSyntheticChildrenTraversal( 171 ValueObject::GetValueForExpressionPathOptions:: 172 SyntheticChildrenTraversal::None), 173 nullptr) 174 .get(); 175 if (m_pair_ptr) { 176 auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true)); 177 if (!__i_) { 178 m_pair_ptr = nullptr; 179 return false; 180 } 181 CompilerType pair_type(__i_->GetCompilerType().GetTypeTemplateArgument(0)); 182 std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr; 183 pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); 184 if (!pair_type) { 185 m_pair_ptr = nullptr; 186 return false; 187 } 188 189 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); 190 m_pair_ptr = nullptr; 191 if (addr && addr!=LLDB_INVALID_ADDRESS) { 192 ClangASTContext *ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); 193 if (!ast_ctx) 194 return false; 195 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), { 196 {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 197 {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 198 {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, 199 {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, 200 {"payload",pair_type} 201 }); 202 DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0)); 203 ProcessSP process_sp(target_sp->GetProcessSP()); 204 Status error; 205 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error); 206 if (error.Fail()) 207 return false; 208 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 209 auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type); 210 if (pair_sp) 211 m_pair_sp = pair_sp->GetChildAtIndex(4,true); 212 } 213 } 214 } 215 216 return false; 217 } 218 219 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 220 CalculateNumChildren() { 221 return 2; 222 } 223 224 lldb::ValueObjectSP 225 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 226 size_t idx) { 227 if (m_pair_ptr) 228 return m_pair_ptr->GetChildAtIndex(idx, true); 229 if (m_pair_sp) 230 return m_pair_sp->GetChildAtIndex(idx, true); 231 return lldb::ValueObjectSP(); 232 } 233 234 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 235 MightHaveChildren() { 236 return true; 237 } 238 239 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 240 GetIndexOfChildWithName(const ConstString &name) { 241 if (name == ConstString("first")) 242 return 0; 243 if (name == ConstString("second")) 244 return 1; 245 return UINT32_MAX; 246 } 247 248 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 249 ~LibCxxMapIteratorSyntheticFrontEnd() { 250 // this will be deleted when its parent dies (since it's a child object) 251 // delete m_pair_ptr; 252 } 253 254 SyntheticChildrenFrontEnd * 255 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 256 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 257 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 258 : nullptr); 259 } 260 261 /* 262 (lldb) fr var ibeg --raw --ptr-depth 1 -T 263 (std::__1::__wrap_iter<int *>) ibeg = { 264 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { 265 (int) *__i = 1 266 } 267 } 268 */ 269 270 SyntheticChildrenFrontEnd * 271 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( 272 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 273 static ConstString g_item_name; 274 if (!g_item_name) 275 g_item_name.SetCString("__i"); 276 return (valobj_sp 277 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) 278 : nullptr); 279 } 280 281 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 282 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 283 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(), 284 m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) { 285 if (valobj_sp) 286 Update(); 287 } 288 289 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 290 CalculateNumChildren() { 291 return (m_cntrl ? 1 : 0); 292 } 293 294 lldb::ValueObjectSP 295 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( 296 size_t idx) { 297 if (!m_cntrl) 298 return lldb::ValueObjectSP(); 299 300 ValueObjectSP valobj_sp = m_backend.GetSP(); 301 if (!valobj_sp) 302 return lldb::ValueObjectSP(); 303 304 if (idx == 0) 305 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); 306 307 if (idx > 2) 308 return lldb::ValueObjectSP(); 309 310 if (idx == 1) { 311 if (!m_count_sp) { 312 ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName( 313 ConstString("__shared_owners_"), true)); 314 if (!shared_owners_sp) 315 return lldb::ValueObjectSP(); 316 uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0); 317 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 318 m_count_sp = CreateValueObjectFromData( 319 "count", data, valobj_sp->GetExecutionContextRef(), 320 shared_owners_sp->GetCompilerType()); 321 } 322 return m_count_sp; 323 } else /* if (idx == 2) */ 324 { 325 if (!m_weak_count_sp) { 326 ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName( 327 ConstString("__shared_weak_owners_"), true)); 328 if (!shared_weak_owners_sp) 329 return lldb::ValueObjectSP(); 330 uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0); 331 DataExtractor data(&count, 8, m_byte_order, m_ptr_size); 332 m_weak_count_sp = CreateValueObjectFromData( 333 "count", data, valobj_sp->GetExecutionContextRef(), 334 shared_weak_owners_sp->GetCompilerType()); 335 } 336 return m_weak_count_sp; 337 } 338 } 339 340 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { 341 m_count_sp.reset(); 342 m_weak_count_sp.reset(); 343 m_cntrl = nullptr; 344 345 ValueObjectSP valobj_sp = m_backend.GetSP(); 346 if (!valobj_sp) 347 return false; 348 349 TargetSP target_sp(valobj_sp->GetTargetSP()); 350 if (!target_sp) 351 return false; 352 353 m_byte_order = target_sp->GetArchitecture().GetByteOrder(); 354 m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize(); 355 356 lldb::ValueObjectSP cntrl_sp( 357 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); 358 359 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular 360 // dependency 361 return false; 362 } 363 364 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 365 MightHaveChildren() { 366 return true; 367 } 368 369 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 370 GetIndexOfChildWithName(const ConstString &name) { 371 if (name == ConstString("__ptr_")) 372 return 0; 373 if (name == ConstString("count")) 374 return 1; 375 if (name == ConstString("weak_count")) 376 return 2; 377 return UINT32_MAX; 378 } 379 380 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: 381 ~LibcxxSharedPtrSyntheticFrontEnd() = default; 382 383 SyntheticChildrenFrontEnd * 384 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( 385 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 386 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp) 387 : nullptr); 388 } 389 390 bool lldb_private::formatters::LibcxxContainerSummaryProvider( 391 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 392 if (valobj.IsPointerType()) { 393 uint64_t value = valobj.GetValueAsUnsigned(0); 394 if (!value) 395 return false; 396 stream.Printf("0x%016" PRIx64 " ", value); 397 } 398 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr, 399 nullptr, nullptr, &valobj, false, false); 400 } 401 402 // the field layout in a libc++ string (cap, side, data or data, size, cap) 403 enum LibcxxStringLayoutMode { 404 eLibcxxStringLayoutModeCSD = 0, 405 eLibcxxStringLayoutModeDSC = 1, 406 eLibcxxStringLayoutModeInvalid = 0xffff 407 }; 408 409 // this function abstracts away the layout and mode details of a libc++ string 410 // and returns the address of the data and the size ready for callers to 411 // consume 412 static bool ExtractLibcxxStringInfo(ValueObject &valobj, 413 ValueObjectSP &location_sp, 414 uint64_t &size) { 415 ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); 416 if (!D) 417 return false; 418 419 ValueObjectSP layout_decider( 420 D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0}))); 421 422 // this child should exist 423 if (!layout_decider) 424 return false; 425 426 ConstString g_data_name("__data_"); 427 ConstString g_size_name("__size_"); 428 bool short_mode = false; // this means the string is in short-mode and the 429 // data is stored inline 430 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) 431 ? eLibcxxStringLayoutModeDSC 432 : eLibcxxStringLayoutModeCSD; 433 uint64_t size_mode_value = 0; 434 435 if (layout == eLibcxxStringLayoutModeDSC) { 436 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); 437 if (!size_mode) 438 return false; 439 440 if (size_mode->GetName() != g_size_name) { 441 // we are hitting the padding structure, move along 442 size_mode = D->GetChildAtIndexPath({1, 1, 1}); 443 if (!size_mode) 444 return false; 445 } 446 447 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 448 short_mode = ((size_mode_value & 0x80) == 0); 449 } else { 450 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); 451 if (!size_mode) 452 return false; 453 454 size_mode_value = (size_mode->GetValueAsUnsigned(0)); 455 short_mode = ((size_mode_value & 1) == 0); 456 } 457 458 if (short_mode) { 459 ValueObjectSP s(D->GetChildAtIndex(1, true)); 460 if (!s) 461 return false; 462 location_sp = s->GetChildAtIndex( 463 (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true); 464 size = (layout == eLibcxxStringLayoutModeDSC) 465 ? size_mode_value 466 : ((size_mode_value >> 1) % 256); 467 return (location_sp.get() != nullptr); 468 } else { 469 ValueObjectSP l(D->GetChildAtIndex(0, true)); 470 if (!l) 471 return false; 472 // we can use the layout_decider object as the data pointer 473 location_sp = (layout == eLibcxxStringLayoutModeDSC) 474 ? layout_decider 475 : l->GetChildAtIndex(2, true); 476 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 477 if (!size_vo || !location_sp) 478 return false; 479 size = size_vo->GetValueAsUnsigned(0); 480 return true; 481 } 482 } 483 484 bool lldb_private::formatters::LibcxxWStringSummaryProvider( 485 ValueObject &valobj, Stream &stream, 486 const TypeSummaryOptions &summary_options) { 487 uint64_t size = 0; 488 ValueObjectSP location_sp; 489 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 490 return false; 491 if (size == 0) { 492 stream.Printf("L\"\""); 493 return true; 494 } 495 if (!location_sp) 496 return false; 497 498 DataExtractor extractor; 499 500 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 501 502 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 503 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 504 if (size > max_size) { 505 size = max_size; 506 options.SetIsTruncated(true); 507 } 508 } 509 location_sp->GetPointeeData(extractor, 0, size); 510 511 // std::wstring::size() is measured in 'characters', not bytes 512 auto wchar_t_size = valobj.GetTargetSP() 513 ->GetScratchClangASTContext() 514 ->GetBasicType(lldb::eBasicTypeWChar) 515 .GetByteSize(nullptr); 516 517 options.SetData(extractor); 518 options.SetStream(&stream); 519 options.SetPrefixToken("L"); 520 options.SetQuote('"'); 521 options.SetSourceSize(size); 522 options.SetBinaryZeroIsTerminator(false); 523 524 switch (wchar_t_size) { 525 case 1: 526 StringPrinter::ReadBufferAndDumpToStream< 527 lldb_private::formatters::StringPrinter::StringElementType::UTF8>( 528 options); 529 break; 530 531 case 2: 532 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 533 lldb_private::formatters::StringPrinter::StringElementType::UTF16>( 534 options); 535 break; 536 537 case 4: 538 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< 539 lldb_private::formatters::StringPrinter::StringElementType::UTF32>( 540 options); 541 break; 542 543 default: 544 stream.Printf("size for wchar_t is not valid"); 545 return true; 546 } 547 548 return true; 549 } 550 551 bool lldb_private::formatters::LibcxxStringSummaryProvider( 552 ValueObject &valobj, Stream &stream, 553 const TypeSummaryOptions &summary_options) { 554 uint64_t size = 0; 555 ValueObjectSP location_sp; 556 557 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 558 return false; 559 560 if (size == 0) { 561 stream.Printf("\"\""); 562 return true; 563 } 564 565 if (!location_sp) 566 return false; 567 568 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); 569 570 DataExtractor extractor; 571 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { 572 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); 573 if (size > max_size) { 574 size = max_size; 575 options.SetIsTruncated(true); 576 } 577 } 578 location_sp->GetPointeeData(extractor, 0, size); 579 580 options.SetData(extractor); 581 options.SetStream(&stream); 582 options.SetPrefixToken(nullptr); 583 options.SetQuote('"'); 584 options.SetSourceSize(size); 585 options.SetBinaryZeroIsTerminator(false); 586 StringPrinter::ReadBufferAndDumpToStream< 587 StringPrinter::StringElementType::ASCII>(options); 588 589 return true; 590 } 591 592 class LibcxxFunctionFrontEnd : public SyntheticValueProviderFrontEnd { 593 public: 594 LibcxxFunctionFrontEnd(ValueObject &backend) 595 : SyntheticValueProviderFrontEnd(backend) {} 596 597 lldb::ValueObjectSP GetSyntheticValue() override { 598 static ConstString g___f_("__f_"); 599 return m_backend.GetChildMemberWithName(g___f_, true); 600 } 601 }; 602 603 SyntheticChildrenFrontEnd * 604 lldb_private::formatters::LibcxxFunctionFrontEndCreator( 605 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 606 if (valobj_sp) 607 return new LibcxxFunctionFrontEnd(*valobj_sp); 608 return nullptr; 609 } 610