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