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