1 //===-- NSSet.cpp -----------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "NSSet.h" 10 11 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" 12 #include "lldb/Core/ValueObject.h" 13 #include "lldb/Core/ValueObjectConstResult.h" 14 #include "lldb/DataFormatters/FormattersHelpers.h" 15 #include "lldb/Symbol/ClangASTContext.h" 16 #include "lldb/Target/Language.h" 17 #include "lldb/Target/ObjCLanguageRuntime.h" 18 #include "lldb/Target/Target.h" 19 #include "lldb/Utility/DataBufferHeap.h" 20 #include "lldb/Utility/Endian.h" 21 #include "lldb/Utility/Status.h" 22 #include "lldb/Utility/Stream.h" 23 24 using namespace lldb; 25 using namespace lldb_private; 26 using namespace lldb_private::formatters; 27 28 std::map<ConstString, CXXFunctionSummaryFormat::Callback> & 29 NSSet_Additionals::GetAdditionalSummaries() { 30 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map; 31 return g_map; 32 } 33 34 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> & 35 NSSet_Additionals::GetAdditionalSynthetics() { 36 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> 37 g_map; 38 return g_map; 39 } 40 41 namespace lldb_private { 42 namespace formatters { 43 class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd { 44 public: 45 NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 46 47 ~NSSetISyntheticFrontEnd() override; 48 49 size_t CalculateNumChildren() override; 50 51 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 52 53 bool Update() override; 54 55 bool MightHaveChildren() override; 56 57 size_t GetIndexOfChildWithName(ConstString name) override; 58 59 private: 60 struct DataDescriptor_32 { 61 uint32_t _used : 26; 62 uint32_t _szidx : 6; 63 }; 64 65 struct DataDescriptor_64 { 66 uint64_t _used : 58; 67 uint32_t _szidx : 6; 68 }; 69 70 struct SetItemDescriptor { 71 lldb::addr_t item_ptr; 72 lldb::ValueObjectSP valobj_sp; 73 }; 74 75 ExecutionContextRef m_exe_ctx_ref; 76 uint8_t m_ptr_size; 77 DataDescriptor_32 *m_data_32; 78 DataDescriptor_64 *m_data_64; 79 lldb::addr_t m_data_ptr; 80 std::vector<SetItemDescriptor> m_children; 81 }; 82 83 template <typename D32, typename D64> 84 class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 85 public: 86 GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 87 88 ~GenericNSSetMSyntheticFrontEnd() override; 89 90 size_t CalculateNumChildren() override; 91 92 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 93 94 bool Update() override; 95 96 bool MightHaveChildren() override; 97 98 size_t GetIndexOfChildWithName(ConstString name) override; 99 100 private: 101 102 struct SetItemDescriptor { 103 lldb::addr_t item_ptr; 104 lldb::ValueObjectSP valobj_sp; 105 }; 106 107 ExecutionContextRef m_exe_ctx_ref; 108 uint8_t m_ptr_size; 109 D32 *m_data_32; 110 D64 *m_data_64; 111 std::vector<SetItemDescriptor> m_children; 112 }; 113 114 namespace Foundation1300 { 115 struct DataDescriptor_32 { 116 uint32_t _used : 26; 117 uint32_t _size; 118 uint32_t _mutations; 119 uint32_t _objs_addr; 120 }; 121 122 struct DataDescriptor_64 { 123 uint64_t _used : 58; 124 uint64_t _size; 125 uint64_t _mutations; 126 uint64_t _objs_addr; 127 }; 128 129 using NSSetMSyntheticFrontEnd = 130 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 131 } 132 133 namespace Foundation1428 { 134 struct DataDescriptor_32 { 135 uint32_t _used : 26; 136 uint32_t _size; 137 uint32_t _objs_addr; 138 uint32_t _mutations; 139 }; 140 141 struct DataDescriptor_64 { 142 uint64_t _used : 58; 143 uint64_t _size; 144 uint64_t _objs_addr; 145 uint64_t _mutations; 146 }; 147 148 using NSSetMSyntheticFrontEnd = 149 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 150 } 151 152 namespace Foundation1437 { 153 struct DataDescriptor_32 { 154 uint32_t _cow; 155 // __table storage 156 uint32_t _objs_addr; 157 uint32_t _muts; 158 uint32_t _used : 26; 159 uint32_t _szidx : 6; 160 }; 161 162 struct DataDescriptor_64 { 163 uint64_t _cow; 164 // __Table storage 165 uint64_t _objs_addr; 166 uint32_t _muts; 167 uint32_t _used : 26; 168 uint32_t _szidx : 6; 169 }; 170 171 using NSSetMSyntheticFrontEnd = 172 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 173 174 template <typename DD> 175 uint64_t 176 __NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr, 177 Status &error) { 178 const lldb::addr_t start_of_descriptor = 179 valobj_addr + process.GetAddressByteSize(); 180 DD descriptor = DD(); 181 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor), 182 error); 183 if (error.Fail()) { 184 return 0; 185 } 186 return descriptor._used; 187 } 188 189 uint64_t 190 __NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, 191 Status &error) { 192 if (process.GetAddressByteSize() == 4) { 193 return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error); 194 } else { 195 return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error); 196 } 197 } 198 } 199 200 class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 201 public: 202 NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 203 204 ~NSSetCodeRunningSyntheticFrontEnd() override; 205 206 size_t CalculateNumChildren() override; 207 208 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 209 210 bool Update() override; 211 212 bool MightHaveChildren() override; 213 214 size_t GetIndexOfChildWithName(ConstString name) override; 215 }; 216 } // namespace formatters 217 } // namespace lldb_private 218 219 template <bool cf_style> 220 bool lldb_private::formatters::NSSetSummaryProvider( 221 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 222 static ConstString g_TypeHint("NSSet"); 223 224 ProcessSP process_sp = valobj.GetProcessSP(); 225 if (!process_sp) 226 return false; 227 228 ObjCLanguageRuntime *runtime = 229 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime( 230 lldb::eLanguageTypeObjC); 231 232 if (!runtime) 233 return false; 234 235 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 236 runtime->GetClassDescriptor(valobj)); 237 238 if (!descriptor || !descriptor->IsValid()) 239 return false; 240 241 uint32_t ptr_size = process_sp->GetAddressByteSize(); 242 bool is_64bit = (ptr_size == 8); 243 244 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 245 246 if (!valobj_addr) 247 return false; 248 249 uint64_t value = 0; 250 251 ConstString class_name_cs = descriptor->GetClassName(); 252 const char *class_name = class_name_cs.GetCString(); 253 254 if (!class_name || !*class_name) 255 return false; 256 257 if (!strcmp(class_name, "__NSSetI") || 258 !strcmp(class_name, "__NSOrderedSetI")) { 259 Status error; 260 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 261 ptr_size, 0, error); 262 if (error.Fail()) 263 return false; 264 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 265 } else if (!strcmp(class_name, "__NSSetM")) { 266 AppleObjCRuntime *apple_runtime = 267 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 268 Status error; 269 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) { 270 value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error); 271 } else { 272 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 273 ptr_size, 0, error); 274 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 275 } 276 if (error.Fail()) 277 return false; 278 } else { 279 auto &map(NSSet_Additionals::GetAdditionalSummaries()); 280 auto iter = map.find(class_name_cs), end = map.end(); 281 if (iter != end) 282 return iter->second(valobj, stream, options); 283 else 284 return false; 285 } 286 287 std::string prefix, suffix; 288 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 289 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 290 suffix)) { 291 prefix.clear(); 292 suffix.clear(); 293 } 294 } 295 296 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element", 297 value == 1 ? "" : "s", suffix.c_str()); 298 return true; 299 } 300 301 SyntheticChildrenFrontEnd * 302 lldb_private::formatters::NSSetSyntheticFrontEndCreator( 303 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 304 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 305 if (!process_sp) 306 return nullptr; 307 ObjCLanguageRuntime *runtime = 308 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime( 309 lldb::eLanguageTypeObjC); 310 if (!runtime) 311 return nullptr; 312 313 CompilerType valobj_type(valobj_sp->GetCompilerType()); 314 Flags flags(valobj_type.GetTypeInfo()); 315 316 if (flags.IsClear(eTypeIsPointer)) { 317 Status error; 318 valobj_sp = valobj_sp->AddressOf(error); 319 if (error.Fail() || !valobj_sp) 320 return nullptr; 321 } 322 323 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 324 runtime->GetClassDescriptor(*valobj_sp)); 325 326 if (!descriptor || !descriptor->IsValid()) 327 return nullptr; 328 329 ConstString class_name_cs = descriptor->GetClassName(); 330 const char *class_name = class_name_cs.GetCString(); 331 332 if (!class_name || !*class_name) 333 return nullptr; 334 335 if (!strcmp(class_name, "__NSSetI") || 336 !strcmp(class_name, "__NSOrderedSetI")) { 337 return (new NSSetISyntheticFrontEnd(valobj_sp)); 338 } else if (!strcmp(class_name, "__NSSetM")) { 339 AppleObjCRuntime *apple_runtime = 340 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 341 if (apple_runtime) { 342 if (apple_runtime->GetFoundationVersion() >= 1437) 343 return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp)); 344 else if (apple_runtime->GetFoundationVersion() >= 1428) 345 return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp)); 346 else 347 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp)); 348 } else { 349 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp)); 350 } 351 } else { 352 auto &map(NSSet_Additionals::GetAdditionalSynthetics()); 353 auto iter = map.find(class_name_cs), end = map.end(); 354 if (iter != end) 355 return iter->second(synth, valobj_sp); 356 return nullptr; 357 } 358 } 359 360 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd( 361 lldb::ValueObjectSP valobj_sp) 362 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 363 m_data_32(nullptr), m_data_64(nullptr) { 364 if (valobj_sp) 365 Update(); 366 } 367 368 lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() { 369 delete m_data_32; 370 m_data_32 = nullptr; 371 delete m_data_64; 372 m_data_64 = nullptr; 373 } 374 375 size_t 376 lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName( 377 ConstString name) { 378 const char *item_name = name.GetCString(); 379 uint32_t idx = ExtractIndexFromString(item_name); 380 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 381 return UINT32_MAX; 382 return idx; 383 } 384 385 size_t 386 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() { 387 if (!m_data_32 && !m_data_64) 388 return 0; 389 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 390 } 391 392 bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() { 393 m_children.clear(); 394 delete m_data_32; 395 m_data_32 = nullptr; 396 delete m_data_64; 397 m_data_64 = nullptr; 398 m_ptr_size = 0; 399 ValueObjectSP valobj_sp = m_backend.GetSP(); 400 if (!valobj_sp) 401 return false; 402 if (!valobj_sp) 403 return false; 404 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 405 Status error; 406 if (valobj_sp->IsPointerType()) { 407 valobj_sp = valobj_sp->Dereference(error); 408 if (error.Fail() || !valobj_sp) 409 return false; 410 } 411 error.Clear(); 412 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 413 if (!process_sp) 414 return false; 415 m_ptr_size = process_sp->GetAddressByteSize(); 416 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 417 if (m_ptr_size == 4) { 418 m_data_32 = new DataDescriptor_32(); 419 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 420 error); 421 } else { 422 m_data_64 = new DataDescriptor_64(); 423 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 424 error); 425 } 426 if (error.Fail()) 427 return false; 428 m_data_ptr = data_location + m_ptr_size; 429 return false; 430 } 431 432 bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() { 433 return true; 434 } 435 436 lldb::ValueObjectSP 437 lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) { 438 uint32_t num_children = CalculateNumChildren(); 439 440 if (idx >= num_children) 441 return lldb::ValueObjectSP(); 442 443 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 444 if (!process_sp) 445 return lldb::ValueObjectSP(); 446 447 if (m_children.empty()) { 448 // do the scan phase 449 lldb::addr_t obj_at_idx = 0; 450 451 uint32_t tries = 0; 452 uint32_t test_idx = 0; 453 454 while (tries < num_children) { 455 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size); 456 if (!process_sp) 457 return lldb::ValueObjectSP(); 458 Status error; 459 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 460 if (error.Fail()) 461 return lldb::ValueObjectSP(); 462 463 test_idx++; 464 465 if (!obj_at_idx) 466 continue; 467 tries++; 468 469 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()}; 470 471 m_children.push_back(descriptor); 472 } 473 } 474 475 if (idx >= m_children.size()) // should never happen 476 return lldb::ValueObjectSP(); 477 478 SetItemDescriptor &set_item = m_children[idx]; 479 if (!set_item.valobj_sp) { 480 auto ptr_size = process_sp->GetAddressByteSize(); 481 DataBufferHeap buffer(ptr_size, 0); 482 switch (ptr_size) { 483 case 0: // architecture has no clue?? - fail 484 return lldb::ValueObjectSP(); 485 case 4: 486 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr; 487 break; 488 case 8: 489 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr; 490 break; 491 default: 492 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP"); 493 } 494 StreamString idx_name; 495 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 496 497 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), 498 process_sp->GetByteOrder(), 499 process_sp->GetAddressByteSize()); 500 501 set_item.valobj_sp = CreateValueObjectFromData( 502 idx_name.GetString(), data, m_exe_ctx_ref, 503 m_backend.GetCompilerType().GetBasicTypeFromAST( 504 lldb::eBasicTypeObjCID)); 505 } 506 return set_item.valobj_sp; 507 } 508 509 template <typename D32, typename D64> 510 lldb_private::formatters:: 511 GenericNSSetMSyntheticFrontEnd<D32, D64>::GenericNSSetMSyntheticFrontEnd( 512 lldb::ValueObjectSP valobj_sp) 513 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 514 m_data_32(nullptr), m_data_64(nullptr) { 515 if (valobj_sp) 516 Update(); 517 } 518 519 template <typename D32, typename D64> 520 lldb_private::formatters:: 521 GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd() { 522 delete m_data_32; 523 m_data_32 = nullptr; 524 delete m_data_64; 525 m_data_64 = nullptr; 526 } 527 528 template <typename D32, typename D64> 529 size_t 530 lldb_private::formatters:: 531 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName( 532 ConstString name) { 533 const char *item_name = name.GetCString(); 534 uint32_t idx = ExtractIndexFromString(item_name); 535 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 536 return UINT32_MAX; 537 return idx; 538 } 539 540 template <typename D32, typename D64> 541 size_t 542 lldb_private::formatters:: 543 GenericNSSetMSyntheticFrontEnd<D32, D64>::CalculateNumChildren() { 544 if (!m_data_32 && !m_data_64) 545 return 0; 546 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 547 } 548 549 template <typename D32, typename D64> 550 bool 551 lldb_private::formatters:: 552 GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() { 553 m_children.clear(); 554 ValueObjectSP valobj_sp = m_backend.GetSP(); 555 m_ptr_size = 0; 556 delete m_data_32; 557 m_data_32 = nullptr; 558 delete m_data_64; 559 m_data_64 = nullptr; 560 if (!valobj_sp) 561 return false; 562 if (!valobj_sp) 563 return false; 564 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 565 Status error; 566 if (valobj_sp->IsPointerType()) { 567 valobj_sp = valobj_sp->Dereference(error); 568 if (error.Fail() || !valobj_sp) 569 return false; 570 } 571 error.Clear(); 572 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 573 if (!process_sp) 574 return false; 575 m_ptr_size = process_sp->GetAddressByteSize(); 576 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 577 if (m_ptr_size == 4) { 578 m_data_32 = new D32(); 579 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 580 error); 581 } else { 582 m_data_64 = new D64(); 583 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 584 error); 585 } 586 if (error.Fail()) 587 return false; 588 return false; 589 } 590 591 template <typename D32, typename D64> 592 bool 593 lldb_private::formatters:: 594 GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() { 595 return true; 596 } 597 598 template <typename D32, typename D64> 599 lldb::ValueObjectSP 600 lldb_private::formatters:: 601 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(size_t idx) { 602 lldb::addr_t m_objs_addr = 603 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 604 605 uint32_t num_children = CalculateNumChildren(); 606 607 if (idx >= num_children) 608 return lldb::ValueObjectSP(); 609 610 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 611 if (!process_sp) 612 return lldb::ValueObjectSP(); 613 614 if (m_children.empty()) { 615 // do the scan phase 616 lldb::addr_t obj_at_idx = 0; 617 618 uint32_t tries = 0; 619 uint32_t test_idx = 0; 620 621 while (tries < num_children) { 622 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size); 623 if (!process_sp) 624 return lldb::ValueObjectSP(); 625 Status error; 626 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 627 if (error.Fail()) 628 return lldb::ValueObjectSP(); 629 630 test_idx++; 631 632 if (!obj_at_idx) 633 continue; 634 tries++; 635 636 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()}; 637 638 m_children.push_back(descriptor); 639 } 640 } 641 642 if (idx >= m_children.size()) // should never happen 643 return lldb::ValueObjectSP(); 644 645 SetItemDescriptor &set_item = m_children[idx]; 646 if (!set_item.valobj_sp) { 647 auto ptr_size = process_sp->GetAddressByteSize(); 648 DataBufferHeap buffer(ptr_size, 0); 649 switch (ptr_size) { 650 case 0: // architecture has no clue?? - fail 651 return lldb::ValueObjectSP(); 652 case 4: 653 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr; 654 break; 655 case 8: 656 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr; 657 break; 658 default: 659 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP"); 660 } 661 StreamString idx_name; 662 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 663 664 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), 665 process_sp->GetByteOrder(), 666 process_sp->GetAddressByteSize()); 667 668 set_item.valobj_sp = CreateValueObjectFromData( 669 idx_name.GetString(), data, m_exe_ctx_ref, 670 m_backend.GetCompilerType().GetBasicTypeFromAST( 671 lldb::eBasicTypeObjCID)); 672 } 673 return set_item.valobj_sp; 674 } 675 676 template bool lldb_private::formatters::NSSetSummaryProvider<true>( 677 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); 678 679 template bool lldb_private::formatters::NSSetSummaryProvider<false>( 680 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); 681