1 //===-- NSSet.cpp ---------------------------------------------------------===// 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 #include "CFBasicHash.h" 11 12 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" 13 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 14 #include "lldb/Core/ValueObject.h" 15 #include "lldb/Core/ValueObjectConstResult.h" 16 #include "lldb/DataFormatters/FormattersHelpers.h" 17 #include "lldb/Target/Language.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 class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 84 public: 85 NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 86 87 size_t CalculateNumChildren() override; 88 89 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 90 91 bool Update() override; 92 93 bool MightHaveChildren() override; 94 95 size_t GetIndexOfChildWithName(ConstString name) override; 96 97 private: 98 struct SetItemDescriptor { 99 lldb::addr_t item_ptr; 100 lldb::ValueObjectSP valobj_sp; 101 }; 102 103 ExecutionContextRef m_exe_ctx_ref; 104 uint8_t m_ptr_size; 105 lldb::ByteOrder m_order; 106 107 CFBasicHash m_hashtable; 108 109 CompilerType m_pair_type; 110 std::vector<SetItemDescriptor> m_children; 111 }; 112 113 template <typename D32, typename D64> 114 class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 115 public: 116 GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 117 118 ~GenericNSSetMSyntheticFrontEnd() override; 119 120 size_t CalculateNumChildren() override; 121 122 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 123 124 bool Update() override; 125 126 bool MightHaveChildren() override; 127 128 size_t GetIndexOfChildWithName(ConstString name) override; 129 130 private: 131 132 struct SetItemDescriptor { 133 lldb::addr_t item_ptr; 134 lldb::ValueObjectSP valobj_sp; 135 }; 136 137 ExecutionContextRef m_exe_ctx_ref; 138 uint8_t m_ptr_size; 139 D32 *m_data_32; 140 D64 *m_data_64; 141 std::vector<SetItemDescriptor> m_children; 142 }; 143 144 namespace Foundation1300 { 145 struct DataDescriptor_32 { 146 uint32_t _used : 26; 147 uint32_t _size; 148 uint32_t _mutations; 149 uint32_t _objs_addr; 150 }; 151 152 struct DataDescriptor_64 { 153 uint64_t _used : 58; 154 uint64_t _size; 155 uint64_t _mutations; 156 uint64_t _objs_addr; 157 }; 158 159 using NSSetMSyntheticFrontEnd = 160 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 161 } 162 163 namespace Foundation1428 { 164 struct DataDescriptor_32 { 165 uint32_t _used : 26; 166 uint32_t _size; 167 uint32_t _objs_addr; 168 uint32_t _mutations; 169 }; 170 171 struct DataDescriptor_64 { 172 uint64_t _used : 58; 173 uint64_t _size; 174 uint64_t _objs_addr; 175 uint64_t _mutations; 176 }; 177 178 using NSSetMSyntheticFrontEnd = 179 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 180 } 181 182 namespace Foundation1437 { 183 struct DataDescriptor_32 { 184 uint32_t _cow; 185 // __table storage 186 uint32_t _objs_addr; 187 uint32_t _muts; 188 uint32_t _used : 26; 189 uint32_t _szidx : 6; 190 }; 191 192 struct DataDescriptor_64 { 193 uint64_t _cow; 194 // __Table storage 195 uint64_t _objs_addr; 196 uint32_t _muts; 197 uint32_t _used : 26; 198 uint32_t _szidx : 6; 199 }; 200 201 using NSSetMSyntheticFrontEnd = 202 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 203 204 template <typename DD> 205 uint64_t 206 __NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr, 207 Status &error) { 208 const lldb::addr_t start_of_descriptor = 209 valobj_addr + process.GetAddressByteSize(); 210 DD descriptor = DD(); 211 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor), 212 error); 213 if (error.Fail()) { 214 return 0; 215 } 216 return descriptor._used; 217 } 218 219 uint64_t 220 __NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, 221 Status &error) { 222 if (process.GetAddressByteSize() == 4) { 223 return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error); 224 } else { 225 return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error); 226 } 227 } 228 } 229 230 class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 231 public: 232 NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 233 234 ~NSSetCodeRunningSyntheticFrontEnd() override; 235 236 size_t CalculateNumChildren() override; 237 238 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 239 240 bool Update() override; 241 242 bool MightHaveChildren() override; 243 244 size_t GetIndexOfChildWithName(ConstString name) override; 245 }; 246 } // namespace formatters 247 } // namespace lldb_private 248 249 template <bool cf_style> 250 bool lldb_private::formatters::NSSetSummaryProvider( 251 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 252 static ConstString g_TypeHint("NSSet"); 253 254 ProcessSP process_sp = valobj.GetProcessSP(); 255 if (!process_sp) 256 return false; 257 258 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); 259 260 if (!runtime) 261 return false; 262 263 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 264 runtime->GetClassDescriptor(valobj)); 265 266 if (!descriptor || !descriptor->IsValid()) 267 return false; 268 269 uint32_t ptr_size = process_sp->GetAddressByteSize(); 270 bool is_64bit = (ptr_size == 8); 271 272 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 273 274 if (!valobj_addr) 275 return false; 276 277 uint64_t value = 0; 278 279 ConstString class_name(descriptor->GetClassName()); 280 281 static const ConstString g_SetI("__NSSetI"); 282 static const ConstString g_OrderedSetI("__NSOrderedSetI"); 283 static const ConstString g_SetM("__NSSetM"); 284 static const ConstString g_SetCF("__NSCFSet"); 285 static const ConstString g_SetCFRef("CFSetRef"); 286 287 if (class_name.IsEmpty()) 288 return false; 289 290 if (class_name == g_SetI || class_name == g_OrderedSetI) { 291 Status error; 292 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 293 ptr_size, 0, error); 294 if (error.Fail()) 295 return false; 296 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 297 } else if (class_name == g_SetM) { 298 AppleObjCRuntime *apple_runtime = 299 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 300 Status error; 301 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) { 302 value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error); 303 } else { 304 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 305 ptr_size, 0, error); 306 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 307 } 308 if (error.Fail()) 309 return false; 310 } else if (class_name == g_SetCF || class_name == g_SetCFRef) { 311 ExecutionContext exe_ctx(process_sp); 312 CFBasicHash cfbh; 313 if (!cfbh.Update(valobj_addr, exe_ctx)) 314 return false; 315 value = cfbh.GetCount(); 316 } else { 317 auto &map(NSSet_Additionals::GetAdditionalSummaries()); 318 auto iter = map.find(class_name), end = map.end(); 319 if (iter != end) 320 return iter->second(valobj, stream, options); 321 else 322 return false; 323 } 324 325 std::string prefix, suffix; 326 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 327 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 328 suffix)) { 329 prefix.clear(); 330 suffix.clear(); 331 } 332 } 333 334 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element", 335 value == 1 ? "" : "s", suffix.c_str()); 336 return true; 337 } 338 339 SyntheticChildrenFrontEnd * 340 lldb_private::formatters::NSSetSyntheticFrontEndCreator( 341 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 342 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 343 if (!process_sp) 344 return nullptr; 345 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); 346 if (!runtime) 347 return nullptr; 348 349 CompilerType valobj_type(valobj_sp->GetCompilerType()); 350 Flags flags(valobj_type.GetTypeInfo()); 351 352 if (flags.IsClear(eTypeIsPointer)) { 353 Status error; 354 valobj_sp = valobj_sp->AddressOf(error); 355 if (error.Fail() || !valobj_sp) 356 return nullptr; 357 } 358 359 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 360 runtime->GetClassDescriptor(*valobj_sp)); 361 362 if (!descriptor || !descriptor->IsValid()) 363 return nullptr; 364 365 ConstString class_name = descriptor->GetClassName(); 366 367 static const ConstString g_SetI("__NSSetI"); 368 static const ConstString g_OrderedSetI("__NSOrderedSetI"); 369 static const ConstString g_SetM("__NSSetM"); 370 static const ConstString g_SetCF("__NSCFSet"); 371 static const ConstString g_SetCFRef("CFSetRef"); 372 373 if (class_name.IsEmpty()) 374 return nullptr; 375 376 if (class_name == g_SetI || class_name == g_OrderedSetI) { 377 return (new NSSetISyntheticFrontEnd(valobj_sp)); 378 } else if (class_name == g_SetM) { 379 AppleObjCRuntime *apple_runtime = 380 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 381 if (apple_runtime) { 382 if (apple_runtime->GetFoundationVersion() >= 1437) 383 return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp)); 384 else if (apple_runtime->GetFoundationVersion() >= 1428) 385 return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp)); 386 else 387 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp)); 388 } else { 389 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp)); 390 } 391 } else if (class_name == g_SetCF || class_name == g_SetCFRef) { 392 return (new NSCFSetSyntheticFrontEnd(valobj_sp)); 393 } else { 394 auto &map(NSSet_Additionals::GetAdditionalSynthetics()); 395 auto iter = map.find(class_name), end = map.end(); 396 if (iter != end) 397 return iter->second(synth, valobj_sp); 398 return nullptr; 399 } 400 } 401 402 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd( 403 lldb::ValueObjectSP valobj_sp) 404 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 405 m_data_32(nullptr), m_data_64(nullptr) { 406 if (valobj_sp) 407 Update(); 408 } 409 410 lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() { 411 delete m_data_32; 412 m_data_32 = nullptr; 413 delete m_data_64; 414 m_data_64 = nullptr; 415 } 416 417 size_t 418 lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName( 419 ConstString name) { 420 const char *item_name = name.GetCString(); 421 uint32_t idx = ExtractIndexFromString(item_name); 422 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 423 return UINT32_MAX; 424 return idx; 425 } 426 427 size_t 428 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() { 429 if (!m_data_32 && !m_data_64) 430 return 0; 431 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 432 } 433 434 bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() { 435 m_children.clear(); 436 delete m_data_32; 437 m_data_32 = nullptr; 438 delete m_data_64; 439 m_data_64 = nullptr; 440 m_ptr_size = 0; 441 ValueObjectSP valobj_sp = m_backend.GetSP(); 442 if (!valobj_sp) 443 return false; 444 if (!valobj_sp) 445 return false; 446 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 447 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 448 if (!process_sp) 449 return false; 450 m_ptr_size = process_sp->GetAddressByteSize(); 451 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 452 Status error; 453 if (m_ptr_size == 4) { 454 m_data_32 = new DataDescriptor_32(); 455 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 456 error); 457 } else { 458 m_data_64 = new DataDescriptor_64(); 459 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 460 error); 461 } 462 if (error.Fail()) 463 return false; 464 m_data_ptr = data_location + m_ptr_size; 465 return false; 466 } 467 468 bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() { 469 return true; 470 } 471 472 lldb::ValueObjectSP 473 lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) { 474 uint32_t num_children = CalculateNumChildren(); 475 476 if (idx >= num_children) 477 return lldb::ValueObjectSP(); 478 479 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 480 if (!process_sp) 481 return lldb::ValueObjectSP(); 482 483 if (m_children.empty()) { 484 // do the scan phase 485 lldb::addr_t obj_at_idx = 0; 486 487 uint32_t tries = 0; 488 uint32_t test_idx = 0; 489 490 while (tries < num_children) { 491 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size); 492 if (!process_sp) 493 return lldb::ValueObjectSP(); 494 Status error; 495 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 496 if (error.Fail()) 497 return lldb::ValueObjectSP(); 498 499 test_idx++; 500 501 if (!obj_at_idx) 502 continue; 503 tries++; 504 505 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()}; 506 507 m_children.push_back(descriptor); 508 } 509 } 510 511 if (idx >= m_children.size()) // should never happen 512 return lldb::ValueObjectSP(); 513 514 SetItemDescriptor &set_item = m_children[idx]; 515 if (!set_item.valobj_sp) { 516 auto ptr_size = process_sp->GetAddressByteSize(); 517 DataBufferHeap buffer(ptr_size, 0); 518 switch (ptr_size) { 519 case 0: // architecture has no clue - fail 520 return lldb::ValueObjectSP(); 521 case 4: 522 *reinterpret_cast<uint32_t *>(buffer.GetBytes()) = 523 static_cast<uint32_t>(set_item.item_ptr); 524 break; 525 case 8: 526 *reinterpret_cast<uint64_t *>(buffer.GetBytes()) = 527 static_cast<uint64_t>(set_item.item_ptr); 528 break; 529 default: 530 lldbassert(false && "pointer size is not 4 nor 8"); 531 } 532 StreamString idx_name; 533 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 534 535 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), 536 process_sp->GetByteOrder(), 537 process_sp->GetAddressByteSize()); 538 539 set_item.valobj_sp = CreateValueObjectFromData( 540 idx_name.GetString(), data, m_exe_ctx_ref, 541 m_backend.GetCompilerType().GetBasicTypeFromAST( 542 lldb::eBasicTypeObjCID)); 543 } 544 return set_item.valobj_sp; 545 } 546 547 lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd( 548 lldb::ValueObjectSP valobj_sp) 549 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 550 m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {} 551 552 size_t 553 lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName( 554 ConstString name) { 555 const char *item_name = name.GetCString(); 556 const uint32_t idx = ExtractIndexFromString(item_name); 557 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 558 return UINT32_MAX; 559 return idx; 560 } 561 562 size_t 563 lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() { 564 if (!m_hashtable.IsValid()) 565 return 0; 566 return m_hashtable.GetCount(); 567 } 568 569 bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() { 570 m_children.clear(); 571 ValueObjectSP valobj_sp = m_backend.GetSP(); 572 m_ptr_size = 0; 573 if (!valobj_sp) 574 return false; 575 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 576 577 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 578 if (!process_sp) 579 return false; 580 m_ptr_size = process_sp->GetAddressByteSize(); 581 m_order = process_sp->GetByteOrder(); 582 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref); 583 } 584 585 bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() { 586 return true; 587 } 588 589 lldb::ValueObjectSP 590 lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex( 591 size_t idx) { 592 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer(); 593 594 const uint32_t num_children = CalculateNumChildren(); 595 596 if (idx >= num_children) 597 return lldb::ValueObjectSP(); 598 599 if (m_children.empty()) { 600 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 601 if (!process_sp) 602 return lldb::ValueObjectSP(); 603 604 Status error; 605 lldb::addr_t val_at_idx = 0; 606 607 uint32_t tries = 0; 608 uint32_t test_idx = 0; 609 610 // Iterate over inferior memory, reading value pointers by shifting the 611 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read 612 // fails, otherwise, continue until the number of tries matches the number 613 // of childen. 614 while (tries < num_children) { 615 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 616 617 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 618 if (error.Fail()) 619 return lldb::ValueObjectSP(); 620 621 test_idx++; 622 623 if (!val_at_idx) 624 continue; 625 tries++; 626 627 SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()}; 628 629 m_children.push_back(descriptor); 630 } 631 } 632 633 if (idx >= m_children.size()) // should never happen 634 return lldb::ValueObjectSP(); 635 636 SetItemDescriptor &set_item = m_children[idx]; 637 if (!set_item.valobj_sp) { 638 639 DataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0)); 640 641 switch (m_ptr_size) { 642 case 0: // architecture has no clue - fail 643 return lldb::ValueObjectSP(); 644 case 4: 645 *reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) = 646 static_cast<uint32_t>(set_item.item_ptr); 647 break; 648 case 8: 649 *reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) = 650 static_cast<uint64_t>(set_item.item_ptr); 651 break; 652 default: 653 lldbassert(false && "pointer size is not 4 nor 8"); 654 } 655 StreamString idx_name; 656 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 657 658 DataExtractor data(buffer_sp, m_order, m_ptr_size); 659 660 set_item.valobj_sp = CreateValueObjectFromData( 661 idx_name.GetString(), data, m_exe_ctx_ref, 662 m_backend.GetCompilerType().GetBasicTypeFromAST( 663 lldb::eBasicTypeObjCID)); 664 } 665 666 return set_item.valobj_sp; 667 } 668 669 template <typename D32, typename D64> 670 lldb_private::formatters:: 671 GenericNSSetMSyntheticFrontEnd<D32, D64>::GenericNSSetMSyntheticFrontEnd( 672 lldb::ValueObjectSP valobj_sp) 673 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 674 m_data_32(nullptr), m_data_64(nullptr) { 675 if (valobj_sp) 676 Update(); 677 } 678 679 template <typename D32, typename D64> 680 lldb_private::formatters:: 681 GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd<D32, D64>() { 682 delete m_data_32; 683 m_data_32 = nullptr; 684 delete m_data_64; 685 m_data_64 = nullptr; 686 } 687 688 template <typename D32, typename D64> 689 size_t 690 lldb_private::formatters:: 691 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName( 692 ConstString name) { 693 const char *item_name = name.GetCString(); 694 uint32_t idx = ExtractIndexFromString(item_name); 695 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 696 return UINT32_MAX; 697 return idx; 698 } 699 700 template <typename D32, typename D64> 701 size_t 702 lldb_private::formatters:: 703 GenericNSSetMSyntheticFrontEnd<D32, D64>::CalculateNumChildren() { 704 if (!m_data_32 && !m_data_64) 705 return 0; 706 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 707 } 708 709 template <typename D32, typename D64> 710 bool 711 lldb_private::formatters:: 712 GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() { 713 m_children.clear(); 714 ValueObjectSP valobj_sp = m_backend.GetSP(); 715 m_ptr_size = 0; 716 delete m_data_32; 717 m_data_32 = nullptr; 718 delete m_data_64; 719 m_data_64 = nullptr; 720 if (!valobj_sp) 721 return false; 722 if (!valobj_sp) 723 return false; 724 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 725 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 726 if (!process_sp) 727 return false; 728 m_ptr_size = process_sp->GetAddressByteSize(); 729 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 730 Status error; 731 if (m_ptr_size == 4) { 732 m_data_32 = new D32(); 733 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 734 error); 735 } else { 736 m_data_64 = new D64(); 737 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 738 error); 739 } 740 if (error.Fail()) 741 return false; 742 return false; 743 } 744 745 template <typename D32, typename D64> 746 bool 747 lldb_private::formatters:: 748 GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() { 749 return true; 750 } 751 752 template <typename D32, typename D64> 753 lldb::ValueObjectSP 754 lldb_private::formatters:: 755 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(size_t idx) { 756 lldb::addr_t m_objs_addr = 757 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 758 759 uint32_t num_children = CalculateNumChildren(); 760 761 if (idx >= num_children) 762 return lldb::ValueObjectSP(); 763 764 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 765 if (!process_sp) 766 return lldb::ValueObjectSP(); 767 768 if (m_children.empty()) { 769 // do the scan phase 770 lldb::addr_t obj_at_idx = 0; 771 772 uint32_t tries = 0; 773 uint32_t test_idx = 0; 774 775 while (tries < num_children) { 776 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size); 777 if (!process_sp) 778 return lldb::ValueObjectSP(); 779 Status error; 780 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 781 if (error.Fail()) 782 return lldb::ValueObjectSP(); 783 784 test_idx++; 785 786 if (!obj_at_idx) 787 continue; 788 tries++; 789 790 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()}; 791 792 m_children.push_back(descriptor); 793 } 794 } 795 796 if (idx >= m_children.size()) // should never happen 797 return lldb::ValueObjectSP(); 798 799 SetItemDescriptor &set_item = m_children[idx]; 800 if (!set_item.valobj_sp) { 801 auto ptr_size = process_sp->GetAddressByteSize(); 802 DataBufferHeap buffer(ptr_size, 0); 803 switch (ptr_size) { 804 case 0: // architecture has no clue?? - fail 805 return lldb::ValueObjectSP(); 806 case 4: 807 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr; 808 break; 809 case 8: 810 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr; 811 break; 812 default: 813 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP"); 814 } 815 StreamString idx_name; 816 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 817 818 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), 819 process_sp->GetByteOrder(), 820 process_sp->GetAddressByteSize()); 821 822 set_item.valobj_sp = CreateValueObjectFromData( 823 idx_name.GetString(), data, m_exe_ctx_ref, 824 m_backend.GetCompilerType().GetBasicTypeFromAST( 825 lldb::eBasicTypeObjCID)); 826 } 827 return set_item.valobj_sp; 828 } 829 830 template bool lldb_private::formatters::NSSetSummaryProvider<true>( 831 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); 832 833 template bool lldb_private::formatters::NSSetSummaryProvider<false>( 834 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); 835