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