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 286 if (class_name.IsEmpty()) 287 return false; 288 289 if (class_name == g_SetI || class_name == g_OrderedSetI) { 290 Status error; 291 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 292 ptr_size, 0, error); 293 if (error.Fail()) 294 return false; 295 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 296 } else if (class_name == g_SetM) { 297 AppleObjCRuntime *apple_runtime = 298 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 299 Status error; 300 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) { 301 value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error); 302 } else { 303 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 304 ptr_size, 0, error); 305 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 306 } 307 if (error.Fail()) 308 return false; 309 } else if (class_name == g_SetCF) { 310 ExecutionContext exe_ctx(process_sp); 311 CFBasicHash cfbh; 312 if (!cfbh.Update(valobj_addr, exe_ctx)) 313 return false; 314 value = cfbh.GetCount(); 315 } else { 316 auto &map(NSSet_Additionals::GetAdditionalSummaries()); 317 auto iter = map.find(class_name), end = map.end(); 318 if (iter != end) 319 return iter->second(valobj, stream, options); 320 else 321 return false; 322 } 323 324 std::string prefix, suffix; 325 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 326 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 327 suffix)) { 328 prefix.clear(); 329 suffix.clear(); 330 } 331 } 332 333 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element", 334 value == 1 ? "" : "s", suffix.c_str()); 335 return true; 336 } 337 338 SyntheticChildrenFrontEnd * 339 lldb_private::formatters::NSSetSyntheticFrontEndCreator( 340 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 341 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 342 if (!process_sp) 343 return nullptr; 344 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); 345 if (!runtime) 346 return nullptr; 347 348 CompilerType valobj_type(valobj_sp->GetCompilerType()); 349 Flags flags(valobj_type.GetTypeInfo()); 350 351 if (flags.IsClear(eTypeIsPointer)) { 352 Status error; 353 valobj_sp = valobj_sp->AddressOf(error); 354 if (error.Fail() || !valobj_sp) 355 return nullptr; 356 } 357 358 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 359 runtime->GetClassDescriptor(*valobj_sp)); 360 361 if (!descriptor || !descriptor->IsValid()) 362 return nullptr; 363 364 ConstString class_name = descriptor->GetClassName(); 365 366 static const ConstString g_SetI("__NSSetI"); 367 static const ConstString g_OrderedSetI("__NSOrderedSetI"); 368 static const ConstString g_SetM("__NSSetM"); 369 static const ConstString g_SetCF("__NSCFSet"); 370 371 if (class_name.IsEmpty()) 372 return nullptr; 373 374 if (class_name == g_SetI || class_name == g_OrderedSetI) { 375 return (new NSSetISyntheticFrontEnd(valobj_sp)); 376 } else if (class_name == g_SetM) { 377 AppleObjCRuntime *apple_runtime = 378 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 379 if (apple_runtime) { 380 if (apple_runtime->GetFoundationVersion() >= 1437) 381 return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp)); 382 else if (apple_runtime->GetFoundationVersion() >= 1428) 383 return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp)); 384 else 385 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp)); 386 } else { 387 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp)); 388 } 389 } else if (class_name == g_SetCF) { 390 return (new NSCFSetSyntheticFrontEnd(valobj_sp)); 391 } else { 392 auto &map(NSSet_Additionals::GetAdditionalSynthetics()); 393 auto iter = map.find(class_name), end = map.end(); 394 if (iter != end) 395 return iter->second(synth, valobj_sp); 396 return nullptr; 397 } 398 } 399 400 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd( 401 lldb::ValueObjectSP valobj_sp) 402 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 403 m_data_32(nullptr), m_data_64(nullptr) { 404 if (valobj_sp) 405 Update(); 406 } 407 408 lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() { 409 delete m_data_32; 410 m_data_32 = nullptr; 411 delete m_data_64; 412 m_data_64 = nullptr; 413 } 414 415 size_t 416 lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName( 417 ConstString name) { 418 const char *item_name = name.GetCString(); 419 uint32_t idx = ExtractIndexFromString(item_name); 420 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 421 return UINT32_MAX; 422 return idx; 423 } 424 425 size_t 426 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() { 427 if (!m_data_32 && !m_data_64) 428 return 0; 429 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 430 } 431 432 bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() { 433 m_children.clear(); 434 delete m_data_32; 435 m_data_32 = nullptr; 436 delete m_data_64; 437 m_data_64 = nullptr; 438 m_ptr_size = 0; 439 ValueObjectSP valobj_sp = m_backend.GetSP(); 440 if (!valobj_sp) 441 return false; 442 if (!valobj_sp) 443 return false; 444 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 445 Status error; 446 if (valobj_sp->IsPointerType()) { 447 valobj_sp = valobj_sp->Dereference(error); 448 if (error.Fail() || !valobj_sp) 449 return false; 450 } 451 error.Clear(); 452 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 453 if (!process_sp) 454 return false; 455 m_ptr_size = process_sp->GetAddressByteSize(); 456 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 457 if (m_ptr_size == 4) { 458 m_data_32 = new DataDescriptor_32(); 459 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 460 error); 461 } else { 462 m_data_64 = new DataDescriptor_64(); 463 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 464 error); 465 } 466 if (error.Fail()) 467 return false; 468 m_data_ptr = data_location + m_ptr_size; 469 return false; 470 } 471 472 bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() { 473 return true; 474 } 475 476 lldb::ValueObjectSP 477 lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) { 478 uint32_t num_children = CalculateNumChildren(); 479 480 if (idx >= num_children) 481 return lldb::ValueObjectSP(); 482 483 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 484 if (!process_sp) 485 return lldb::ValueObjectSP(); 486 487 if (m_children.empty()) { 488 // do the scan phase 489 lldb::addr_t obj_at_idx = 0; 490 491 uint32_t tries = 0; 492 uint32_t test_idx = 0; 493 494 while (tries < num_children) { 495 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size); 496 if (!process_sp) 497 return lldb::ValueObjectSP(); 498 Status error; 499 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 500 if (error.Fail()) 501 return lldb::ValueObjectSP(); 502 503 test_idx++; 504 505 if (!obj_at_idx) 506 continue; 507 tries++; 508 509 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()}; 510 511 m_children.push_back(descriptor); 512 } 513 } 514 515 if (idx >= m_children.size()) // should never happen 516 return lldb::ValueObjectSP(); 517 518 SetItemDescriptor &set_item = m_children[idx]; 519 if (!set_item.valobj_sp) { 520 auto ptr_size = process_sp->GetAddressByteSize(); 521 DataBufferHeap buffer(ptr_size, 0); 522 switch (ptr_size) { 523 case 0: // architecture has no clue - fail 524 return lldb::ValueObjectSP(); 525 case 4: 526 *reinterpret_cast<uint32_t *>(buffer.GetBytes()) = 527 static_cast<uint32_t>(set_item.item_ptr); 528 break; 529 case 8: 530 *reinterpret_cast<uint64_t *>(buffer.GetBytes()) = 531 static_cast<uint64_t>(set_item.item_ptr); 532 break; 533 default: 534 lldbassert(false && "pointer size is not 4 nor 8"); 535 } 536 StreamString idx_name; 537 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 538 539 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), 540 process_sp->GetByteOrder(), 541 process_sp->GetAddressByteSize()); 542 543 set_item.valobj_sp = CreateValueObjectFromData( 544 idx_name.GetString(), data, m_exe_ctx_ref, 545 m_backend.GetCompilerType().GetBasicTypeFromAST( 546 lldb::eBasicTypeObjCID)); 547 } 548 return set_item.valobj_sp; 549 } 550 551 lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd( 552 lldb::ValueObjectSP valobj_sp) 553 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 554 m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {} 555 556 size_t 557 lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName( 558 ConstString name) { 559 const char *item_name = name.GetCString(); 560 const uint32_t idx = ExtractIndexFromString(item_name); 561 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 562 return UINT32_MAX; 563 return idx; 564 } 565 566 size_t 567 lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() { 568 if (!m_hashtable.IsValid()) 569 return 0; 570 return m_hashtable.GetCount(); 571 } 572 573 bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() { 574 m_children.clear(); 575 ValueObjectSP valobj_sp = m_backend.GetSP(); 576 m_ptr_size = 0; 577 if (!valobj_sp) 578 return false; 579 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 580 581 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 582 if (!process_sp) 583 return false; 584 m_ptr_size = process_sp->GetAddressByteSize(); 585 m_order = process_sp->GetByteOrder(); 586 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref); 587 } 588 589 bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() { 590 return true; 591 } 592 593 lldb::ValueObjectSP 594 lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex( 595 size_t idx) { 596 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer(); 597 598 const uint32_t num_children = CalculateNumChildren(); 599 600 if (idx >= num_children) 601 return lldb::ValueObjectSP(); 602 603 if (m_children.empty()) { 604 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 605 if (!process_sp) 606 return lldb::ValueObjectSP(); 607 608 Status error; 609 lldb::addr_t val_at_idx = 0; 610 611 uint32_t tries = 0; 612 uint32_t test_idx = 0; 613 614 // Iterate over inferior memory, reading value pointers by shifting the 615 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read 616 // fails, otherwise, continue until the number of tries matches the number 617 // of childen. 618 while (tries < num_children) { 619 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 620 621 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 622 if (error.Fail()) 623 return lldb::ValueObjectSP(); 624 625 test_idx++; 626 627 if (!val_at_idx) 628 continue; 629 tries++; 630 631 SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()}; 632 633 m_children.push_back(descriptor); 634 } 635 } 636 637 if (idx >= m_children.size()) // should never happen 638 return lldb::ValueObjectSP(); 639 640 SetItemDescriptor &set_item = m_children[idx]; 641 if (!set_item.valobj_sp) { 642 643 DataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0)); 644 645 switch (m_ptr_size) { 646 case 0: // architecture has no clue - fail 647 return lldb::ValueObjectSP(); 648 case 4: 649 *reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) = 650 static_cast<uint32_t>(set_item.item_ptr); 651 break; 652 case 8: 653 *reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) = 654 static_cast<uint64_t>(set_item.item_ptr); 655 break; 656 default: 657 lldbassert(false && "pointer size is not 4 nor 8"); 658 } 659 StreamString idx_name; 660 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 661 662 DataExtractor data(buffer_sp, m_order, m_ptr_size); 663 664 set_item.valobj_sp = CreateValueObjectFromData( 665 idx_name.GetString(), data, m_exe_ctx_ref, 666 m_backend.GetCompilerType().GetBasicTypeFromAST( 667 lldb::eBasicTypeObjCID)); 668 } 669 670 return set_item.valobj_sp; 671 } 672 673 template <typename D32, typename D64> 674 lldb_private::formatters:: 675 GenericNSSetMSyntheticFrontEnd<D32, D64>::GenericNSSetMSyntheticFrontEnd( 676 lldb::ValueObjectSP valobj_sp) 677 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 678 m_data_32(nullptr), m_data_64(nullptr) { 679 if (valobj_sp) 680 Update(); 681 } 682 683 template <typename D32, typename D64> 684 lldb_private::formatters:: 685 GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd<D32, D64>() { 686 delete m_data_32; 687 m_data_32 = nullptr; 688 delete m_data_64; 689 m_data_64 = nullptr; 690 } 691 692 template <typename D32, typename D64> 693 size_t 694 lldb_private::formatters:: 695 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName( 696 ConstString name) { 697 const char *item_name = name.GetCString(); 698 uint32_t idx = ExtractIndexFromString(item_name); 699 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 700 return UINT32_MAX; 701 return idx; 702 } 703 704 template <typename D32, typename D64> 705 size_t 706 lldb_private::formatters:: 707 GenericNSSetMSyntheticFrontEnd<D32, D64>::CalculateNumChildren() { 708 if (!m_data_32 && !m_data_64) 709 return 0; 710 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 711 } 712 713 template <typename D32, typename D64> 714 bool 715 lldb_private::formatters:: 716 GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() { 717 m_children.clear(); 718 ValueObjectSP valobj_sp = m_backend.GetSP(); 719 m_ptr_size = 0; 720 delete m_data_32; 721 m_data_32 = nullptr; 722 delete m_data_64; 723 m_data_64 = nullptr; 724 if (!valobj_sp) 725 return false; 726 if (!valobj_sp) 727 return false; 728 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 729 Status error; 730 if (valobj_sp->IsPointerType()) { 731 valobj_sp = valobj_sp->Dereference(error); 732 if (error.Fail() || !valobj_sp) 733 return false; 734 } 735 error.Clear(); 736 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 737 if (!process_sp) 738 return false; 739 m_ptr_size = process_sp->GetAddressByteSize(); 740 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 741 if (m_ptr_size == 4) { 742 m_data_32 = new D32(); 743 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 744 error); 745 } else { 746 m_data_64 = new D64(); 747 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 748 error); 749 } 750 if (error.Fail()) 751 return false; 752 return false; 753 } 754 755 template <typename D32, typename D64> 756 bool 757 lldb_private::formatters:: 758 GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() { 759 return true; 760 } 761 762 template <typename D32, typename D64> 763 lldb::ValueObjectSP 764 lldb_private::formatters:: 765 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(size_t idx) { 766 lldb::addr_t m_objs_addr = 767 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 768 769 uint32_t num_children = CalculateNumChildren(); 770 771 if (idx >= num_children) 772 return lldb::ValueObjectSP(); 773 774 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 775 if (!process_sp) 776 return lldb::ValueObjectSP(); 777 778 if (m_children.empty()) { 779 // do the scan phase 780 lldb::addr_t obj_at_idx = 0; 781 782 uint32_t tries = 0; 783 uint32_t test_idx = 0; 784 785 while (tries < num_children) { 786 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size); 787 if (!process_sp) 788 return lldb::ValueObjectSP(); 789 Status error; 790 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 791 if (error.Fail()) 792 return lldb::ValueObjectSP(); 793 794 test_idx++; 795 796 if (!obj_at_idx) 797 continue; 798 tries++; 799 800 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()}; 801 802 m_children.push_back(descriptor); 803 } 804 } 805 806 if (idx >= m_children.size()) // should never happen 807 return lldb::ValueObjectSP(); 808 809 SetItemDescriptor &set_item = m_children[idx]; 810 if (!set_item.valobj_sp) { 811 auto ptr_size = process_sp->GetAddressByteSize(); 812 DataBufferHeap buffer(ptr_size, 0); 813 switch (ptr_size) { 814 case 0: // architecture has no clue?? - fail 815 return lldb::ValueObjectSP(); 816 case 4: 817 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr; 818 break; 819 case 8: 820 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr; 821 break; 822 default: 823 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP"); 824 } 825 StreamString idx_name; 826 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 827 828 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), 829 process_sp->GetByteOrder(), 830 process_sp->GetAddressByteSize()); 831 832 set_item.valobj_sp = CreateValueObjectFromData( 833 idx_name.GetString(), data, m_exe_ctx_ref, 834 m_backend.GetCompilerType().GetBasicTypeFromAST( 835 lldb::eBasicTypeObjCID)); 836 } 837 return set_item.valobj_sp; 838 } 839 840 template bool lldb_private::formatters::NSSetSummaryProvider<true>( 841 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); 842 843 template bool lldb_private::formatters::NSSetSummaryProvider<false>( 844 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); 845