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