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