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