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 namespace { 102 struct DataDescriptor_32 { 103 uint32_t _used; 104 uint32_t _offset; 105 uint32_t _size : 28; 106 uint64_t _priv1 : 4; 107 uint32_t _priv2; 108 uint32_t _data; 109 }; 110 111 struct DataDescriptor_64 { 112 uint64_t _used; 113 uint64_t _offset; 114 uint64_t _size : 60; 115 uint64_t _priv1 : 4; 116 uint32_t _priv2; 117 uint64_t _data; 118 }; 119 } 120 121 using NSArrayMSyntheticFrontEnd = 122 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 123 } 124 125 namespace Foundation1428 { 126 namespace { 127 struct DataDescriptor_32 { 128 uint32_t _used; 129 uint32_t _offset; 130 uint32_t _size; 131 uint32_t _data; 132 }; 133 134 struct DataDescriptor_64 { 135 uint64_t _used; 136 uint64_t _offset; 137 uint64_t _size; 138 uint64_t _data; 139 }; 140 } 141 142 using NSArrayMSyntheticFrontEnd = 143 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 144 } 145 146 namespace Foundation1437 { 147 template <typename PtrType> 148 struct DataDescriptor { 149 PtrType _cow; 150 // __deque 151 PtrType _data; 152 uint32_t _offset; 153 uint32_t _size; 154 uint32_t _muts; 155 uint32_t _used; 156 }; 157 158 using NSArrayMSyntheticFrontEnd = 159 GenericNSArrayMSyntheticFrontEnd< 160 DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>; 161 162 template <typename DD> 163 uint64_t 164 __NSArrayMSize_Impl(lldb_private::Process &process, 165 lldb::addr_t valobj_addr, Status &error) { 166 const lldb::addr_t start_of_descriptor = 167 valobj_addr + process.GetAddressByteSize(); 168 DD descriptor = DD(); 169 process.ReadMemory(start_of_descriptor, &descriptor, 170 sizeof(descriptor), error); 171 if (error.Fail()) { 172 return 0; 173 } 174 return descriptor._used; 175 } 176 177 uint64_t 178 __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, 179 Status &error) { 180 if (process.GetAddressByteSize() == 4) { 181 return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr, 182 error); 183 } else { 184 return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr, 185 error); 186 } 187 } 188 189 } 190 191 namespace CallStackArray { 192 struct DataDescriptor_32 { 193 uint32_t _data; 194 uint32_t _used; 195 uint32_t _offset; 196 const uint32_t _size = 0; 197 }; 198 199 struct DataDescriptor_64 { 200 uint64_t _data; 201 uint64_t _used; 202 uint64_t _offset; 203 const uint64_t _size = 0; 204 }; 205 206 using NSCallStackArraySyntheticFrontEnd = 207 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 208 } // namespace CallStackArray 209 210 template <typename D32, typename D64, bool Inline> 211 class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd { 212 public: 213 GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 214 215 ~GenericNSArrayISyntheticFrontEnd() override; 216 217 size_t CalculateNumChildren() override; 218 219 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 220 221 bool Update() override; 222 223 bool MightHaveChildren() override; 224 225 size_t GetIndexOfChildWithName(ConstString name) override; 226 227 private: 228 ExecutionContextRef m_exe_ctx_ref; 229 uint8_t m_ptr_size; 230 231 D32 *m_data_32; 232 D64 *m_data_64; 233 CompilerType m_id_type; 234 }; 235 236 namespace Foundation1300 { 237 struct IDD32 { 238 uint32_t used; 239 uint32_t list; 240 }; 241 242 struct IDD64 { 243 uint64_t used; 244 uint64_t list; 245 }; 246 247 using NSArrayISyntheticFrontEnd = 248 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>; 249 } 250 251 namespace Foundation1430 { 252 using NSArrayISyntheticFrontEnd = 253 Foundation1428::NSArrayMSyntheticFrontEnd; 254 } 255 256 namespace Foundation1436 { 257 struct IDD32 { 258 uint32_t used; 259 uint32_t list; // in Inline cases, this is the first element 260 }; 261 262 struct IDD64 { 263 uint64_t used; 264 uint64_t list; // in Inline cases, this is the first element 265 }; 266 267 using NSArrayI_TransferSyntheticFrontEnd = 268 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>; 269 270 using NSArrayISyntheticFrontEnd = 271 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>; 272 273 using NSFrozenArrayMSyntheticFrontEnd = 274 Foundation1437::NSArrayMSyntheticFrontEnd; 275 276 uint64_t 277 __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, 278 Status &error) { 279 return Foundation1437::__NSArrayMSize(process, valobj_addr, error); 280 } 281 } 282 283 namespace ConstantArray { 284 285 struct ConstantArray32 { 286 uint64_t used; 287 uint32_t list; 288 }; 289 290 struct ConstantArray64 { 291 uint64_t used; 292 uint64_t list; 293 }; 294 295 using NSConstantArraySyntheticFrontEnd = 296 GenericNSArrayISyntheticFrontEnd<ConstantArray32, ConstantArray64, false>; 297 } // namespace ConstantArray 298 299 class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd { 300 public: 301 NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 302 303 ~NSArray0SyntheticFrontEnd() override = default; 304 305 size_t CalculateNumChildren() override; 306 307 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 308 309 bool Update() override; 310 311 bool MightHaveChildren() override; 312 313 size_t GetIndexOfChildWithName(ConstString name) override; 314 }; 315 316 class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd { 317 public: 318 NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 319 320 ~NSArray1SyntheticFrontEnd() override = default; 321 322 size_t CalculateNumChildren() override; 323 324 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 325 326 bool Update() override; 327 328 bool MightHaveChildren() override; 329 330 size_t GetIndexOfChildWithName(ConstString name) override; 331 }; 332 } // namespace formatters 333 } // namespace lldb_private 334 335 bool lldb_private::formatters::NSArraySummaryProvider( 336 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 337 static ConstString g_TypeHint("NSArray"); 338 339 ProcessSP process_sp = valobj.GetProcessSP(); 340 if (!process_sp) 341 return false; 342 343 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); 344 345 if (!runtime) 346 return false; 347 348 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 349 runtime->GetClassDescriptor(valobj)); 350 351 if (!descriptor || !descriptor->IsValid()) 352 return false; 353 354 uint32_t ptr_size = process_sp->GetAddressByteSize(); 355 356 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 357 358 if (!valobj_addr) 359 return false; 360 361 uint64_t value = 0; 362 363 ConstString class_name(descriptor->GetClassName()); 364 365 static const ConstString g_NSArrayI("__NSArrayI"); 366 static const ConstString g_NSArrayM("__NSArrayM"); 367 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer"); 368 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM"); 369 static const ConstString g_NSArray0("__NSArray0"); 370 static const ConstString g_NSArray1("__NSSingleObjectArrayI"); 371 static const ConstString g_NSArrayCF("__NSCFArray"); 372 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy"); 373 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable"); 374 static const ConstString g_NSCallStackArray("_NSCallStackArray"); 375 static const ConstString g_NSConstantArray("NSConstantArray"); 376 377 if (class_name.IsEmpty()) 378 return false; 379 380 if (class_name == g_NSArrayI) { 381 Status error; 382 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 383 ptr_size, 0, error); 384 if (error.Fail()) 385 return false; 386 } else if (class_name == g_NSConstantArray) { 387 Status error; 388 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 8, 389 0, error); 390 if (error.Fail()) 391 return false; 392 } else if (class_name == g_NSArrayM) { 393 AppleObjCRuntime *apple_runtime = 394 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 395 Status error; 396 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) { 397 value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error); 398 } else { 399 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 400 ptr_size, 0, error); 401 } 402 if (error.Fail()) 403 return false; 404 } else if (class_name == g_NSArrayI_Transfer) { 405 Status error; 406 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 407 ptr_size, 0, error); 408 if (error.Fail()) 409 return false; 410 } else if (class_name == g_NSFrozenArrayM) { 411 Status error; 412 value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error); 413 if (error.Fail()) 414 return false; 415 } else if (class_name == g_NSArrayMLegacy) { 416 Status error; 417 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 418 ptr_size, 0, error); 419 if (error.Fail()) 420 return false; 421 } else if (class_name == g_NSArrayMImmutable) { 422 Status error; 423 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 424 ptr_size, 0, error); 425 if (error.Fail()) 426 return false; 427 } else if (class_name == g_NSArray0) { 428 value = 0; 429 } else if (class_name == g_NSArray1) { 430 value = 1; 431 } else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) { 432 // __NSCFArray and _NSCallStackArray store the number of elements as a 433 // pointer-sized value at offset `2 * ptr_size`. 434 Status error; 435 value = process_sp->ReadUnsignedIntegerFromMemory( 436 valobj_addr + 2 * ptr_size, ptr_size, 0, error); 437 if (error.Fail()) 438 return false; 439 } else { 440 auto &map(NSArray_Additionals::GetAdditionalSummaries()); 441 auto iter = map.find(class_name), end = map.end(); 442 if (iter != end) 443 return iter->second(valobj, stream, options); 444 else 445 return false; 446 } 447 448 std::string prefix, suffix; 449 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 450 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 451 suffix)) { 452 prefix.clear(); 453 suffix.clear(); 454 } 455 } 456 457 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element", 458 value == 1 ? "" : "s", suffix.c_str()); 459 return true; 460 } 461 462 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontEndBase( 463 lldb::ValueObjectSP valobj_sp) 464 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 465 m_id_type() { 466 if (valobj_sp) { 467 auto *clang_ast_context = ScratchTypeSystemClang::GetForTarget( 468 *valobj_sp->GetExecutionContextRef().GetTargetSP()); 469 if (clang_ast_context) 470 m_id_type = CompilerType( 471 clang_ast_context, 472 clang_ast_context->getASTContext().ObjCBuiltinIdTy.getAsOpaquePtr()); 473 if (valobj_sp->GetProcessSP()) 474 m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize(); 475 } 476 } 477 478 template <typename D32, typename D64> 479 lldb_private::formatters:: 480 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 481 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 482 : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr), 483 m_data_64(nullptr) {} 484 485 size_t 486 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::CalculateNumChildren() { 487 return GetUsedCount(); 488 } 489 490 lldb::ValueObjectSP 491 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex( 492 size_t idx) { 493 if (idx >= CalculateNumChildren()) 494 return lldb::ValueObjectSP(); 495 lldb::addr_t object_at_idx = GetDataAddress(); 496 size_t pyhs_idx = idx; 497 pyhs_idx += GetOffset(); 498 if (GetSize() <= pyhs_idx) 499 pyhs_idx -= GetSize(); 500 object_at_idx += (pyhs_idx * m_ptr_size); 501 StreamString idx_name; 502 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 503 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx, 504 m_exe_ctx_ref, m_id_type); 505 } 506 507 template <typename D32, typename D64> 508 bool 509 lldb_private::formatters:: 510 GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() { 511 ValueObjectSP valobj_sp = m_backend.GetSP(); 512 m_ptr_size = 0; 513 delete m_data_32; 514 m_data_32 = nullptr; 515 delete m_data_64; 516 m_data_64 = nullptr; 517 if (!valobj_sp) 518 return false; 519 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 520 Status error; 521 error.Clear(); 522 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 523 if (!process_sp) 524 return false; 525 m_ptr_size = process_sp->GetAddressByteSize(); 526 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 527 if (m_ptr_size == 4) { 528 m_data_32 = new D32(); 529 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 530 error); 531 } else { 532 m_data_64 = new D64(); 533 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 534 error); 535 } 536 if (error.Fail()) 537 return false; 538 return false; 539 } 540 541 bool 542 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::MightHaveChildren() { 543 return true; 544 } 545 546 size_t 547 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName( 548 ConstString name) { 549 const char *item_name = name.GetCString(); 550 uint32_t idx = ExtractIndexFromString(item_name); 551 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 552 return UINT32_MAX; 553 return idx; 554 } 555 556 template <typename D32, typename D64> 557 lldb_private::formatters:: 558 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 559 ~GenericNSArrayMSyntheticFrontEnd<D32, D64>() { 560 delete m_data_32; 561 m_data_32 = nullptr; 562 delete m_data_64; 563 m_data_64 = nullptr; 564 } 565 566 template <typename D32, typename D64> 567 lldb::addr_t 568 lldb_private::formatters:: 569 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 570 GenericNSArrayMSyntheticFrontEnd::GetDataAddress() { 571 if (!m_data_32 && !m_data_64) 572 return LLDB_INVALID_ADDRESS; 573 return m_data_32 ? m_data_32->_data : m_data_64->_data; 574 } 575 576 template <typename D32, typename D64> 577 uint64_t 578 lldb_private::formatters:: 579 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 580 GenericNSArrayMSyntheticFrontEnd::GetUsedCount() { 581 if (!m_data_32 && !m_data_64) 582 return 0; 583 return m_data_32 ? m_data_32->_used : m_data_64->_used; 584 } 585 586 template <typename D32, typename D64> 587 uint64_t 588 lldb_private::formatters:: 589 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 590 GenericNSArrayMSyntheticFrontEnd::GetOffset() { 591 if (!m_data_32 && !m_data_64) 592 return 0; 593 return m_data_32 ? m_data_32->_offset : m_data_64->_offset; 594 } 595 596 template <typename D32, typename D64> 597 uint64_t 598 lldb_private::formatters:: 599 GenericNSArrayMSyntheticFrontEnd<D32, D64>:: 600 GenericNSArrayMSyntheticFrontEnd::GetSize() { 601 if (!m_data_32 && !m_data_64) 602 return 0; 603 return m_data_32 ? m_data_32->_size : m_data_64->_size; 604 } 605 606 template <typename D32, typename D64, bool Inline> 607 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: 608 GenericNSArrayISyntheticFrontEnd( 609 lldb::ValueObjectSP valobj_sp) 610 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 611 m_data_32(nullptr), m_data_64(nullptr) { 612 if (valobj_sp) { 613 CompilerType type = valobj_sp->GetCompilerType(); 614 if (type) { 615 auto *clang_ast_context = ScratchTypeSystemClang::GetForTarget( 616 *valobj_sp->GetExecutionContextRef().GetTargetSP()); 617 if (clang_ast_context) 618 m_id_type = clang_ast_context->GetType( 619 clang_ast_context->getASTContext().ObjCBuiltinIdTy); 620 } 621 } 622 } 623 624 template <typename D32, typename D64, bool Inline> 625 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: 626 ~GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>() { 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 auto *clang_ast_context = 784 ScratchTypeSystemClang::GetForTarget(*m_backend.GetTargetSP()); 785 if (clang_ast_context) { 786 CompilerType id_type( 787 clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID)); 788 return m_backend.GetSyntheticChildAtOffset( 789 m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true, 790 g_zero); 791 } 792 } 793 return lldb::ValueObjectSP(); 794 } 795 796 SyntheticChildrenFrontEnd * 797 lldb_private::formatters::NSArraySyntheticFrontEndCreator( 798 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 799 if (!valobj_sp) 800 return nullptr; 801 802 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 803 if (!process_sp) 804 return nullptr; 805 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>( 806 ObjCLanguageRuntime::Get(*process_sp)); 807 if (!runtime) 808 return nullptr; 809 810 CompilerType valobj_type(valobj_sp->GetCompilerType()); 811 Flags flags(valobj_type.GetTypeInfo()); 812 813 if (flags.IsClear(eTypeIsPointer)) { 814 Status error; 815 valobj_sp = valobj_sp->AddressOf(error); 816 if (error.Fail() || !valobj_sp) 817 return nullptr; 818 } 819 820 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 821 runtime->GetClassDescriptor(*valobj_sp)); 822 823 if (!descriptor || !descriptor->IsValid()) 824 return nullptr; 825 826 ConstString class_name(descriptor->GetClassName()); 827 828 static const ConstString g_NSArrayI("__NSArrayI"); 829 static const ConstString g_NSConstantArray("NSConstantArray"); 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 return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp)); 848 } else if (class_name == g_NSArrayI_Transfer) { 849 return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp)); 850 } else if (class_name == g_NSConstantArray) { 851 return new ConstantArray::NSConstantArraySyntheticFrontEnd(valobj_sp); 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 if (class_name == g_NSCallStackArray) { 866 return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp)); 867 } else { 868 auto &map(NSArray_Additionals::GetAdditionalSynthetics()); 869 auto iter = map.find(class_name), end = map.end(); 870 if (iter != end) 871 return iter->second(synth, valobj_sp); 872 } 873 874 return nullptr; 875 } 876