1 //===-- NSArray.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 "clang/AST/ASTContext.h" 11 12 #include "Cocoa.h" 13 14 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" 15 #include "lldb/Core/ValueObject.h" 16 #include "lldb/Core/ValueObjectConstResult.h" 17 #include "lldb/DataFormatters/FormattersHelpers.h" 18 #include "lldb/Expression/FunctionCaller.h" 19 #include "lldb/Symbol/ClangASTContext.h" 20 #include "lldb/Target/Language.h" 21 #include "lldb/Target/ObjCLanguageRuntime.h" 22 #include "lldb/Target/Target.h" 23 #include "lldb/Utility/DataBufferHeap.h" 24 #include "lldb/Utility/Endian.h" 25 #include "lldb/Utility/Status.h" 26 #include "lldb/Utility/Stream.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 using namespace lldb_private::formatters; 31 32 namespace lldb_private { 33 namespace formatters { 34 std::map<ConstString, CXXFunctionSummaryFormat::Callback> & 35 NSArray_Additionals::GetAdditionalSummaries() { 36 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map; 37 return g_map; 38 } 39 40 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> & 41 NSArray_Additionals::GetAdditionalSynthetics() { 42 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> 43 g_map; 44 return g_map; 45 } 46 47 class NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd { 48 public: 49 NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp); 50 51 ~NSArrayMSyntheticFrontEndBase() override = default; 52 53 size_t CalculateNumChildren() override; 54 55 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 56 57 bool Update() override = 0; 58 59 bool MightHaveChildren() override; 60 61 size_t GetIndexOfChildWithName(const ConstString &name) override; 62 63 protected: 64 virtual lldb::addr_t GetDataAddress() = 0; 65 66 virtual uint64_t GetUsedCount() = 0; 67 68 virtual uint64_t GetOffset() = 0; 69 70 virtual uint64_t GetSize() = 0; 71 72 ExecutionContextRef m_exe_ctx_ref; 73 uint8_t m_ptr_size; 74 CompilerType m_id_type; 75 }; 76 77 template <typename D32, typename D64> 78 class GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase { 79 public: 80 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 81 82 ~GenericNSArrayMSyntheticFrontEnd() override; 83 84 bool Update() override; 85 86 protected: 87 lldb::addr_t GetDataAddress() override; 88 89 uint64_t GetUsedCount() override; 90 91 uint64_t GetOffset() override; 92 93 uint64_t GetSize() override; 94 95 private: 96 D32 *m_data_32; 97 D64 *m_data_64; 98 }; 99 100 namespace Foundation109 { 101 struct DataDescriptor_32 { 102 uint32_t _used; 103 uint32_t _priv1 : 2; 104 uint32_t _size : 30; 105 uint32_t _priv2 : 2; 106 uint32_t _offset : 30; 107 uint32_t _priv3; 108 uint32_t _data; 109 }; 110 111 struct DataDescriptor_64 { 112 uint64_t _used; 113 uint64_t _priv1 : 2; 114 uint64_t _size : 62; 115 uint64_t _priv2 : 2; 116 uint64_t _offset : 62; 117 uint32_t _priv3; 118 uint64_t _data; 119 }; 120 121 using NSArrayMSyntheticFrontEnd = 122 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 123 } 124 125 namespace Foundation1010 { 126 struct DataDescriptor_32 { 127 uint32_t _used; 128 uint32_t _offset; 129 uint32_t _size : 28; 130 uint64_t _priv1 : 4; 131 uint32_t _priv2; 132 uint32_t _data; 133 }; 134 135 struct DataDescriptor_64 { 136 uint64_t _used; 137 uint64_t _offset; 138 uint64_t _size : 60; 139 uint64_t _priv1 : 4; 140 uint32_t _priv2; 141 uint64_t _data; 142 }; 143 144 using NSArrayMSyntheticFrontEnd = 145 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 146 } 147 148 namespace Foundation1428 { 149 struct DataDescriptor_32 { 150 uint32_t _used; 151 uint32_t _offset; 152 uint32_t _size; 153 uint32_t _data; 154 }; 155 156 struct DataDescriptor_64 { 157 uint64_t _used; 158 uint64_t _offset; 159 uint64_t _size; 160 uint64_t _data; 161 }; 162 163 using NSArrayMSyntheticFrontEnd = 164 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 165 } 166 167 namespace Foundation1437 { 168 template <typename PtrType> 169 struct DataDescriptor { 170 PtrType _cow; 171 // __deque 172 PtrType _data; 173 uint32_t _offset; 174 uint32_t _size; 175 union { 176 PtrType _mutations; 177 struct { 178 uint32_t _muts; 179 uint32_t _used; 180 }; 181 }; 182 }; 183 184 using NSArrayMSyntheticFrontEnd = 185 GenericNSArrayMSyntheticFrontEnd< 186 DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>; 187 188 template <typename DD> 189 uint64_t 190 __NSArrayMSize_Impl(lldb_private::Process &process, 191 lldb::addr_t valobj_addr, Status &error) { 192 const lldb::addr_t start_of_descriptor = 193 valobj_addr + process.GetAddressByteSize(); 194 DD descriptor = DD(); 195 process.ReadMemory(start_of_descriptor, &descriptor, 196 sizeof(descriptor), error); 197 if (error.Fail()) { 198 return 0; 199 } 200 return descriptor._used; 201 } 202 203 uint64_t 204 __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, 205 Status &error) { 206 if (process.GetAddressByteSize() == 4) { 207 return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr, 208 error); 209 } else { 210 return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr, 211 error); 212 } 213 } 214 215 } 216 217 template <typename D32, typename D64, bool Inline> 218 class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd { 219 public: 220 GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 221 222 ~GenericNSArrayISyntheticFrontEnd() override; 223 224 size_t CalculateNumChildren() override; 225 226 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 227 228 bool Update() override; 229 230 bool MightHaveChildren() override; 231 232 size_t GetIndexOfChildWithName(const ConstString &name) override; 233 234 private: 235 ExecutionContextRef m_exe_ctx_ref; 236 uint8_t m_ptr_size; 237 238 D32 *m_data_32; 239 D64 *m_data_64; 240 CompilerType m_id_type; 241 }; 242 243 namespace Foundation1300 { 244 struct IDD32 { 245 uint32_t used; 246 uint32_t list; 247 }; 248 249 struct IDD64 { 250 uint64_t used; 251 uint64_t list; 252 }; 253 254 using NSArrayISyntheticFrontEnd = 255 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>; 256 } 257 258 namespace Foundation1430 { 259 using NSArrayISyntheticFrontEnd = 260 Foundation1428::NSArrayMSyntheticFrontEnd; 261 } 262 263 namespace Foundation1436 { 264 struct IDD32 { 265 uint32_t used; 266 uint32_t list; // in Inline cases, this is the first element 267 }; 268 269 struct IDD64 { 270 uint64_t used; 271 uint64_t list; // in Inline cases, this is the first element 272 }; 273 274 using NSArrayI_TransferSyntheticFrontEnd = 275 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>; 276 277 using NSArrayISyntheticFrontEnd = 278 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>; 279 280 using NSFrozenArrayMSyntheticFrontEnd = 281 Foundation1437::NSArrayMSyntheticFrontEnd; 282 283 uint64_t 284 __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, 285 Status &error) { 286 return Foundation1437::__NSArrayMSize(process, valobj_addr, error); 287 } 288 } 289 290 class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd { 291 public: 292 NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 293 294 ~NSArray0SyntheticFrontEnd() override = default; 295 296 size_t CalculateNumChildren() override; 297 298 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 299 300 bool Update() override; 301 302 bool MightHaveChildren() override; 303 304 size_t GetIndexOfChildWithName(const ConstString &name) override; 305 }; 306 307 class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd { 308 public: 309 NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 310 311 ~NSArray1SyntheticFrontEnd() override = default; 312 313 size_t CalculateNumChildren() override; 314 315 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 316 317 bool Update() override; 318 319 bool MightHaveChildren() override; 320 321 size_t GetIndexOfChildWithName(const ConstString &name) override; 322 }; 323 } // namespace formatters 324 } // namespace lldb_private 325 326 bool lldb_private::formatters::NSArraySummaryProvider( 327 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 328 static ConstString g_TypeHint("NSArray"); 329 330 ProcessSP process_sp = valobj.GetProcessSP(); 331 if (!process_sp) 332 return false; 333 334 ObjCLanguageRuntime *runtime = 335 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime( 336 lldb::eLanguageTypeObjC); 337 338 if (!runtime) 339 return false; 340 341 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 342 runtime->GetClassDescriptor(valobj)); 343 344 if (!descriptor || !descriptor->IsValid()) 345 return false; 346 347 uint32_t ptr_size = process_sp->GetAddressByteSize(); 348 349 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 350 351 if (!valobj_addr) 352 return false; 353 354 uint64_t value = 0; 355 356 ConstString class_name(descriptor->GetClassName()); 357 358 static const ConstString g_NSArrayI("__NSArrayI"); 359 static const ConstString g_NSArrayM("__NSArrayM"); 360 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer"); 361 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM"); 362 static const ConstString g_NSArray0("__NSArray0"); 363 static const ConstString g_NSArray1("__NSSingleObjectArrayI"); 364 static const ConstString g_NSArrayCF("__NSCFArray"); 365 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy"); 366 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable"); 367 368 if (class_name.IsEmpty()) 369 return false; 370 371 if (class_name == g_NSArrayI) { 372 Status error; 373 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 374 ptr_size, 0, error); 375 if (error.Fail()) 376 return false; 377 } else if (class_name == g_NSArrayM) { 378 AppleObjCRuntime *apple_runtime = 379 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 380 Status error; 381 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) { 382 value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error); 383 } else { 384 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 385 ptr_size, 0, error); 386 } 387 if (error.Fail()) 388 return false; 389 } else if (class_name == g_NSArrayI_Transfer) { 390 Status error; 391 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 392 ptr_size, 0, error); 393 if (error.Fail()) 394 return false; 395 } else if (class_name == g_NSFrozenArrayM) { 396 Status error; 397 value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error); 398 if (error.Fail()) 399 return false; 400 } else if (class_name == g_NSArrayMLegacy) { 401 Status error; 402 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 403 ptr_size, 0, error); 404 if (error.Fail()) 405 return false; 406 } else if (class_name == g_NSArrayMImmutable) { 407 Status error; 408 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 409 ptr_size, 0, error); 410 if (error.Fail()) 411 return false; 412 } else if (class_name == g_NSArray0) { 413 value = 0; 414 } else if (class_name == g_NSArray1) { 415 value = 1; 416 } else if (class_name == g_NSArrayCF) { 417 Status error; 418 value = process_sp->ReadUnsignedIntegerFromMemory( 419 valobj_addr + 2 * ptr_size, ptr_size, 0, error); 420 if (error.Fail()) 421 return false; 422 } else { 423 auto &map(NSArray_Additionals::GetAdditionalSummaries()); 424 auto iter = map.find(class_name), end = map.end(); 425 if (iter != end) 426 return iter->second(valobj, stream, options); 427 else 428 return false; 429 } 430 431 std::string prefix, suffix; 432 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 433 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 434 suffix)) { 435 prefix.clear(); 436 suffix.clear(); 437 } 438 } 439 440 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element", 441 value == 1 ? "" : "s", suffix.c_str()); 442 return true; 443 } 444 445 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontEndBase( 446 lldb::ValueObjectSP valobj_sp) 447 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 448 m_id_type() { 449 if (valobj_sp) { 450 clang::ASTContext *ast = valobj_sp->GetExecutionContextRef() 451 .GetTargetSP() 452 ->GetScratchClangASTContext() 453 ->getASTContext(); 454 if (ast) 455 m_id_type = CompilerType(ast, ast->ObjCBuiltinIdTy); 456 if (valobj_sp->GetProcessSP()) 457 m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize(); 458 } 459 } 460 461 template <typename D32, typename D64> 462 lldb_private::formatters:: 463 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 464 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 465 : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr), 466 m_data_64(nullptr) {} 467 468 size_t 469 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::CalculateNumChildren() { 470 return GetUsedCount(); 471 } 472 473 lldb::ValueObjectSP 474 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex( 475 size_t idx) { 476 if (idx >= CalculateNumChildren()) 477 return lldb::ValueObjectSP(); 478 lldb::addr_t object_at_idx = GetDataAddress(); 479 size_t pyhs_idx = idx; 480 pyhs_idx += GetOffset(); 481 if (GetSize() <= pyhs_idx) 482 pyhs_idx -= GetSize(); 483 object_at_idx += (pyhs_idx * m_ptr_size); 484 StreamString idx_name; 485 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 486 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx, 487 m_exe_ctx_ref, m_id_type); 488 } 489 490 template <typename D32, typename D64> 491 bool 492 lldb_private::formatters:: 493 GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() { 494 ValueObjectSP valobj_sp = m_backend.GetSP(); 495 m_ptr_size = 0; 496 delete m_data_32; 497 m_data_32 = nullptr; 498 delete m_data_64; 499 m_data_64 = nullptr; 500 if (!valobj_sp) 501 return false; 502 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 503 Status error; 504 error.Clear(); 505 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 506 if (!process_sp) 507 return false; 508 m_ptr_size = process_sp->GetAddressByteSize(); 509 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 510 if (m_ptr_size == 4) { 511 m_data_32 = new D32(); 512 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 513 error); 514 } else { 515 m_data_64 = new D64(); 516 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 517 error); 518 } 519 if (error.Fail()) 520 return false; 521 return false; 522 } 523 524 bool 525 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::MightHaveChildren() { 526 return true; 527 } 528 529 size_t 530 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName( 531 const ConstString &name) { 532 const char *item_name = name.GetCString(); 533 uint32_t idx = ExtractIndexFromString(item_name); 534 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 535 return UINT32_MAX; 536 return idx; 537 } 538 539 template <typename D32, typename D64> 540 lldb_private::formatters:: 541 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 542 ~GenericNSArrayMSyntheticFrontEnd() { 543 delete m_data_32; 544 m_data_32 = nullptr; 545 delete m_data_64; 546 m_data_64 = nullptr; 547 } 548 549 template <typename D32, typename D64> 550 lldb::addr_t 551 lldb_private::formatters:: 552 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 553 GenericNSArrayMSyntheticFrontEnd::GetDataAddress() { 554 if (!m_data_32 && !m_data_64) 555 return LLDB_INVALID_ADDRESS; 556 return m_data_32 ? m_data_32->_data : m_data_64->_data; 557 } 558 559 template <typename D32, typename D64> 560 uint64_t 561 lldb_private::formatters:: 562 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 563 GenericNSArrayMSyntheticFrontEnd::GetUsedCount() { 564 if (!m_data_32 && !m_data_64) 565 return 0; 566 return m_data_32 ? m_data_32->_used : m_data_64->_used; 567 } 568 569 template <typename D32, typename D64> 570 uint64_t 571 lldb_private::formatters:: 572 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 573 GenericNSArrayMSyntheticFrontEnd::GetOffset() { 574 if (!m_data_32 && !m_data_64) 575 return 0; 576 return m_data_32 ? m_data_32->_offset : m_data_64->_offset; 577 } 578 579 template <typename D32, typename D64> 580 uint64_t 581 lldb_private::formatters:: 582 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 583 GenericNSArrayMSyntheticFrontEnd::GetSize() { 584 if (!m_data_32 && !m_data_64) 585 return 0; 586 return m_data_32 ? m_data_32->_size : m_data_64->_size; 587 } 588 589 template <typename D32, typename D64, bool Inline> 590 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: 591 GenericNSArrayISyntheticFrontEnd( 592 lldb::ValueObjectSP valobj_sp) 593 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 594 m_data_32(nullptr), m_data_64(nullptr) { 595 if (valobj_sp) { 596 CompilerType type = valobj_sp->GetCompilerType(); 597 if (type) { 598 ClangASTContext *ast = valobj_sp->GetExecutionContextRef() 599 .GetTargetSP() 600 ->GetScratchClangASTContext(); 601 if (ast) 602 m_id_type = CompilerType(ast->getASTContext(), 603 ast->getASTContext()->ObjCBuiltinIdTy); 604 } 605 } 606 } 607 608 template <typename D32, typename D64, bool Inline> 609 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: 610 ~GenericNSArrayISyntheticFrontEnd() { 611 delete m_data_32; 612 m_data_32 = nullptr; 613 delete m_data_64; 614 m_data_64 = nullptr; 615 } 616 617 template <typename D32, typename D64, bool Inline> 618 size_t 619 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: 620 GetIndexOfChildWithName(const ConstString &name) { 621 const char *item_name = name.GetCString(); 622 uint32_t idx = ExtractIndexFromString(item_name); 623 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 624 return UINT32_MAX; 625 return idx; 626 } 627 628 template <typename D32, typename D64, bool Inline> 629 size_t 630 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: 631 CalculateNumChildren() { 632 return m_data_32 ? m_data_32->used : m_data_64->used; 633 } 634 635 template <typename D32, typename D64, bool Inline> 636 bool 637 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: 638 Update() { 639 ValueObjectSP valobj_sp = m_backend.GetSP(); 640 m_ptr_size = 0; 641 delete m_data_32; 642 m_data_32 = nullptr; 643 delete m_data_64; 644 m_data_64 = nullptr; 645 if (!valobj_sp) 646 return false; 647 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 648 Status error; 649 error.Clear(); 650 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 651 if (!process_sp) 652 return false; 653 m_ptr_size = process_sp->GetAddressByteSize(); 654 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 655 if (m_ptr_size == 4) { 656 m_data_32 = new D32(); 657 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 658 error); 659 } else { 660 m_data_64 = new D64(); 661 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 662 error); 663 } 664 if (error.Fail()) 665 return false; 666 return false; 667 } 668 669 template <typename D32, typename D64, bool Inline> 670 bool 671 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: 672 MightHaveChildren() { 673 return true; 674 } 675 676 template <typename D32, typename D64, bool Inline> 677 lldb::ValueObjectSP 678 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: 679 GetChildAtIndex(size_t idx) { 680 if (idx >= CalculateNumChildren()) 681 return lldb::ValueObjectSP(); 682 lldb::addr_t object_at_idx; 683 if (Inline) { 684 object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size; 685 object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header 686 object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer 687 } else { 688 object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list; 689 } 690 object_at_idx += (idx * m_ptr_size); 691 692 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 693 if (!process_sp) 694 return lldb::ValueObjectSP(); 695 Status error; 696 if (error.Fail()) 697 return lldb::ValueObjectSP(); 698 StreamString idx_name; 699 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 700 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx, 701 m_exe_ctx_ref, m_id_type); 702 } 703 704 lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd( 705 lldb::ValueObjectSP valobj_sp) 706 : SyntheticChildrenFrontEnd(*valobj_sp) {} 707 708 size_t 709 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName( 710 const ConstString &name) { 711 return UINT32_MAX; 712 } 713 714 size_t 715 lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() { 716 return 0; 717 } 718 719 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() { 720 return false; 721 } 722 723 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() { 724 return false; 725 } 726 727 lldb::ValueObjectSP 728 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex( 729 size_t idx) { 730 return lldb::ValueObjectSP(); 731 } 732 733 lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd( 734 lldb::ValueObjectSP valobj_sp) 735 : SyntheticChildrenFrontEnd(*valobj_sp.get()) {} 736 737 size_t 738 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName( 739 const ConstString &name) { 740 static const ConstString g_zero("[0]"); 741 742 if (name == g_zero) 743 return 0; 744 745 return UINT32_MAX; 746 } 747 748 size_t 749 lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() { 750 return 1; 751 } 752 753 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() { 754 return false; 755 } 756 757 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() { 758 return true; 759 } 760 761 lldb::ValueObjectSP 762 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex( 763 size_t idx) { 764 static const ConstString g_zero("[0]"); 765 766 if (idx == 0) { 767 CompilerType id_type( 768 m_backend.GetTargetSP()->GetScratchClangASTContext()->GetBasicType( 769 lldb::eBasicTypeObjCID)); 770 return m_backend.GetSyntheticChildAtOffset( 771 m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true, g_zero); 772 } 773 return lldb::ValueObjectSP(); 774 } 775 776 SyntheticChildrenFrontEnd * 777 lldb_private::formatters::NSArraySyntheticFrontEndCreator( 778 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 779 if (!valobj_sp) 780 return nullptr; 781 782 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 783 if (!process_sp) 784 return nullptr; 785 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>( 786 process_sp->GetObjCLanguageRuntime()); 787 if (!runtime) 788 return nullptr; 789 790 CompilerType valobj_type(valobj_sp->GetCompilerType()); 791 Flags flags(valobj_type.GetTypeInfo()); 792 793 if (flags.IsClear(eTypeIsPointer)) { 794 Status error; 795 valobj_sp = valobj_sp->AddressOf(error); 796 if (error.Fail() || !valobj_sp) 797 return nullptr; 798 } 799 800 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 801 runtime->GetClassDescriptor(*valobj_sp)); 802 803 if (!descriptor || !descriptor->IsValid()) 804 return nullptr; 805 806 ConstString class_name(descriptor->GetClassName()); 807 808 static const ConstString g_NSArrayI("__NSArrayI"); 809 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer"); 810 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM"); 811 static const ConstString g_NSArrayM("__NSArrayM"); 812 static const ConstString g_NSArray0("__NSArray0"); 813 static const ConstString g_NSArray1("__NSSingleObjectArrayI"); 814 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy"); 815 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable"); 816 817 if (class_name.IsEmpty()) 818 return nullptr; 819 820 if (class_name == g_NSArrayI) { 821 if (runtime->GetFoundationVersion() >= 1436) 822 return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp)); 823 if (runtime->GetFoundationVersion() >= 1430) 824 return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp)); 825 else 826 return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp)); 827 } else if (class_name == g_NSArrayI_Transfer) { 828 return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp)); 829 } else if (class_name == g_NSArray0) { 830 } else if (class_name == g_NSFrozenArrayM) { 831 return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp)); 832 } else if (class_name == g_NSArray0) { 833 return (new NSArray0SyntheticFrontEnd(valobj_sp)); 834 } else if (class_name == g_NSArray1) { 835 return (new NSArray1SyntheticFrontEnd(valobj_sp)); 836 } else if (class_name == g_NSArrayM) { 837 if (runtime->GetFoundationVersion() >= 1437) 838 return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp)); 839 if (runtime->GetFoundationVersion() >= 1428) 840 return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp)); 841 if (runtime->GetFoundationVersion() >= 1100) 842 return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp)); 843 else 844 return (new Foundation109::NSArrayMSyntheticFrontEnd(valobj_sp)); 845 } else { 846 auto &map(NSArray_Additionals::GetAdditionalSynthetics()); 847 auto iter = map.find(class_name), end = map.end(); 848 if (iter != end) 849 return iter->second(synth, valobj_sp); 850 } 851 852 return nullptr; 853 } 854