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 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 #include "clang/AST/ASTContext.h" 14 15 // Project includes 16 #include "Cocoa.h" 17 18 #include "lldb/Core/DataBufferHeap.h" 19 #include "lldb/Core/Error.h" 20 #include "lldb/Core/Stream.h" 21 #include "lldb/Core/ValueObject.h" 22 #include "lldb/Core/ValueObjectConstResult.h" 23 #include "lldb/DataFormatters/FormattersHelpers.h" 24 #include "lldb/Expression/FunctionCaller.h" 25 #include "lldb/Host/Endian.h" 26 #include "lldb/Symbol/ClangASTContext.h" 27 #include "lldb/Target/Language.h" 28 #include "lldb/Target/ObjCLanguageRuntime.h" 29 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" 30 #include "lldb/Target/Target.h" 31 32 using namespace lldb; 33 using namespace lldb_private; 34 using namespace lldb_private::formatters; 35 36 namespace lldb_private { 37 namespace formatters { 38 class NSArrayMSyntheticFrontEnd : public SyntheticChildrenFrontEnd 39 { 40 public: 41 NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); 42 43 ~NSArrayMSyntheticFrontEnd() override = default; 44 45 size_t 46 CalculateNumChildren() override; 47 48 lldb::ValueObjectSP 49 GetChildAtIndex(size_t idx) override; 50 51 bool 52 Update() override = 0; 53 54 bool 55 MightHaveChildren() override; 56 57 size_t 58 GetIndexOfChildWithName(const ConstString &name) override; 59 60 protected: 61 virtual lldb::addr_t 62 GetDataAddress () = 0; 63 64 virtual uint64_t 65 GetUsedCount () = 0; 66 67 virtual uint64_t 68 GetOffset () = 0; 69 70 virtual uint64_t 71 GetSize () = 0; 72 73 ExecutionContextRef m_exe_ctx_ref; 74 uint8_t m_ptr_size; 75 CompilerType m_id_type; 76 std::vector<lldb::ValueObjectSP> m_children; 77 }; 78 79 class NSArrayMSyntheticFrontEnd_109 : public NSArrayMSyntheticFrontEnd 80 { 81 public: 82 NSArrayMSyntheticFrontEnd_109 (lldb::ValueObjectSP valobj_sp); 83 84 ~NSArrayMSyntheticFrontEnd_109() override; 85 86 bool 87 Update() override; 88 89 protected: 90 lldb::addr_t 91 GetDataAddress() override; 92 93 uint64_t 94 GetUsedCount() override; 95 96 uint64_t 97 GetOffset() override; 98 99 uint64_t 100 GetSize() override; 101 102 private: 103 struct DataDescriptor_32 104 { 105 uint32_t _used; 106 uint32_t _priv1 : 2 ; 107 uint32_t _size : 30; 108 uint32_t _priv2 : 2; 109 uint32_t _offset : 30; 110 uint32_t _priv3; 111 uint32_t _data; 112 }; 113 114 struct DataDescriptor_64 115 { 116 uint64_t _used; 117 uint64_t _priv1 : 2 ; 118 uint64_t _size : 62; 119 uint64_t _priv2 : 2; 120 uint64_t _offset : 62; 121 uint32_t _priv3; 122 uint64_t _data; 123 }; 124 125 DataDescriptor_32 *m_data_32; 126 DataDescriptor_64 *m_data_64; 127 }; 128 129 class NSArrayMSyntheticFrontEnd_1010 : public NSArrayMSyntheticFrontEnd 130 { 131 public: 132 NSArrayMSyntheticFrontEnd_1010 (lldb::ValueObjectSP valobj_sp); 133 134 ~NSArrayMSyntheticFrontEnd_1010() override; 135 136 bool 137 Update() override; 138 139 protected: 140 lldb::addr_t 141 GetDataAddress() override; 142 143 uint64_t 144 GetUsedCount() override; 145 146 uint64_t 147 GetOffset() override; 148 149 uint64_t 150 GetSize() override; 151 152 private: 153 struct DataDescriptor_32 154 { 155 uint32_t _used; 156 uint32_t _offset; 157 uint32_t _size : 28; 158 uint64_t _priv1 : 4; 159 uint32_t _priv2; 160 uint32_t _data; 161 }; 162 163 struct DataDescriptor_64 164 { 165 uint64_t _used; 166 uint64_t _offset; 167 uint64_t _size : 60; 168 uint64_t _priv1 : 4; 169 uint32_t _priv2; 170 uint64_t _data; 171 }; 172 173 DataDescriptor_32 *m_data_32; 174 DataDescriptor_64 *m_data_64; 175 }; 176 177 class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd 178 { 179 public: 180 NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); 181 182 ~NSArrayISyntheticFrontEnd() override = default; 183 184 size_t 185 CalculateNumChildren() override; 186 187 lldb::ValueObjectSP 188 GetChildAtIndex(size_t idx) override; 189 190 bool 191 Update() override; 192 193 bool 194 MightHaveChildren() override; 195 196 size_t 197 GetIndexOfChildWithName(const ConstString &name) override; 198 199 private: 200 ExecutionContextRef m_exe_ctx_ref; 201 uint8_t m_ptr_size; 202 uint64_t m_items; 203 lldb::addr_t m_data_ptr; 204 CompilerType m_id_type; 205 std::vector<lldb::ValueObjectSP> m_children; 206 }; 207 208 class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd 209 { 210 public: 211 NSArray0SyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); 212 213 ~NSArray0SyntheticFrontEnd() override = default; 214 215 size_t 216 CalculateNumChildren() override; 217 218 lldb::ValueObjectSP 219 GetChildAtIndex(size_t idx) override; 220 221 bool 222 Update() override; 223 224 bool 225 MightHaveChildren() override; 226 227 size_t 228 GetIndexOfChildWithName(const ConstString &name) override; 229 }; 230 } // namespace formatters 231 } // namespace lldb_private 232 233 bool 234 lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 235 { 236 static ConstString g_TypeHint("NSArray"); 237 238 ProcessSP process_sp = valobj.GetProcessSP(); 239 if (!process_sp) 240 return false; 241 242 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 243 244 if (!runtime) 245 return false; 246 247 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 248 249 if (!descriptor.get() || !descriptor->IsValid()) 250 return false; 251 252 uint32_t ptr_size = process_sp->GetAddressByteSize(); 253 254 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 255 256 if (!valobj_addr) 257 return false; 258 259 uint64_t value = 0; 260 261 const char* class_name = descriptor->GetClassName().GetCString(); 262 263 if (!class_name || !*class_name) 264 return false; 265 266 if (!strcmp(class_name,"__NSArrayI")) 267 { 268 Error error; 269 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 270 if (error.Fail()) 271 return false; 272 } 273 else if (!strcmp(class_name,"__NSArrayM")) 274 { 275 Error error; 276 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 277 if (error.Fail()) 278 return false; 279 } 280 else if (!strcmp(class_name,"__NSArray0")) 281 { 282 value = 0; 283 } 284 else if (!strcmp(class_name,"__NSCFArray")) 285 { 286 Error error; 287 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error); 288 if (error.Fail()) 289 return false; 290 } 291 else 292 return false; 293 294 std::string prefix,suffix; 295 if (Language* language = Language::FindPlugin(options.GetLanguage())) 296 { 297 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix)) 298 { 299 prefix.clear(); 300 suffix.clear(); 301 } 302 } 303 304 stream.Printf("%s%" PRIu64 " %s%s%s", 305 prefix.c_str(), 306 value, 307 "element", 308 value == 1 ? "" : "s", 309 suffix.c_str()); 310 return true; 311 } 312 313 lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 314 SyntheticChildrenFrontEnd(*valobj_sp), 315 m_exe_ctx_ref(), 316 m_ptr_size(8), 317 m_id_type(), 318 m_children() 319 { 320 if (valobj_sp) 321 { 322 clang::ASTContext *ast = valobj_sp->GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext()->getASTContext(); 323 if (ast) 324 m_id_type = CompilerType(ast, ast->ObjCBuiltinIdTy); 325 if (valobj_sp->GetProcessSP()) 326 m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize(); 327 } 328 } 329 330 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::NSArrayMSyntheticFrontEnd_109 (lldb::ValueObjectSP valobj_sp) : 331 NSArrayMSyntheticFrontEnd(valobj_sp), 332 m_data_32(NULL), 333 m_data_64(NULL) 334 { 335 } 336 337 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::NSArrayMSyntheticFrontEnd_1010 (lldb::ValueObjectSP valobj_sp) : 338 NSArrayMSyntheticFrontEnd(valobj_sp), 339 m_data_32(NULL), 340 m_data_64(NULL) 341 { 342 } 343 344 size_t 345 lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren () 346 { 347 return GetUsedCount(); 348 } 349 350 lldb::ValueObjectSP 351 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx) 352 { 353 if (idx >= CalculateNumChildren()) 354 return lldb::ValueObjectSP(); 355 lldb::addr_t object_at_idx = GetDataAddress(); 356 size_t pyhs_idx = idx; 357 pyhs_idx += GetOffset(); 358 if (GetSize() <= pyhs_idx) 359 pyhs_idx -= GetSize(); 360 object_at_idx += (pyhs_idx * m_ptr_size); 361 StreamString idx_name; 362 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 363 lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(), 364 object_at_idx, 365 m_exe_ctx_ref, 366 m_id_type); 367 m_children.push_back(retval_sp); 368 return retval_sp; 369 } 370 371 bool 372 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::Update() 373 { 374 m_children.clear(); 375 ValueObjectSP valobj_sp = m_backend.GetSP(); 376 m_ptr_size = 0; 377 delete m_data_32; 378 m_data_32 = NULL; 379 delete m_data_64; 380 m_data_64 = NULL; 381 if (!valobj_sp) 382 return false; 383 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 384 Error error; 385 error.Clear(); 386 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 387 if (!process_sp) 388 return false; 389 m_ptr_size = process_sp->GetAddressByteSize(); 390 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 391 if (m_ptr_size == 4) 392 { 393 m_data_32 = new DataDescriptor_32(); 394 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 395 } 396 else 397 { 398 m_data_64 = new DataDescriptor_64(); 399 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 400 } 401 if (error.Fail()) 402 return false; 403 return false; 404 } 405 406 bool 407 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::Update() 408 { 409 m_children.clear(); 410 ValueObjectSP valobj_sp = m_backend.GetSP(); 411 m_ptr_size = 0; 412 delete m_data_32; 413 m_data_32 = NULL; 414 delete m_data_64; 415 m_data_64 = NULL; 416 if (!valobj_sp) 417 return false; 418 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 419 Error error; 420 error.Clear(); 421 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 422 if (!process_sp) 423 return false; 424 m_ptr_size = process_sp->GetAddressByteSize(); 425 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 426 if (m_ptr_size == 4) 427 { 428 m_data_32 = new DataDescriptor_32(); 429 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 430 } 431 else 432 { 433 m_data_64 = new DataDescriptor_64(); 434 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 435 } 436 if (error.Fail()) 437 return false; 438 return false; 439 } 440 441 bool 442 lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren () 443 { 444 return true; 445 } 446 447 size_t 448 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 449 { 450 const char* item_name = name.GetCString(); 451 uint32_t idx = ExtractIndexFromString(item_name); 452 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 453 return UINT32_MAX; 454 return idx; 455 } 456 457 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::~NSArrayMSyntheticFrontEnd_109() 458 { 459 delete m_data_32; 460 m_data_32 = NULL; 461 delete m_data_64; 462 m_data_64 = NULL; 463 } 464 465 lldb::addr_t 466 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetDataAddress () 467 { 468 if (!m_data_32 && !m_data_64) 469 return LLDB_INVALID_ADDRESS; 470 return m_data_32 ? m_data_32->_data : 471 m_data_64->_data; 472 } 473 474 uint64_t 475 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetUsedCount () 476 { 477 if (!m_data_32 && !m_data_64) 478 return 0; 479 return m_data_32 ? m_data_32->_used : 480 m_data_64->_used; 481 } 482 483 uint64_t 484 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetOffset () 485 { 486 if (!m_data_32 && !m_data_64) 487 return 0; 488 return m_data_32 ? m_data_32->_offset : 489 m_data_64->_offset; 490 } 491 492 uint64_t 493 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetSize () 494 { 495 if (!m_data_32 && !m_data_64) 496 return 0; 497 return m_data_32 ? m_data_32->_size : 498 m_data_64->_size; 499 } 500 501 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::~NSArrayMSyntheticFrontEnd_1010() 502 { 503 delete m_data_32; 504 m_data_32 = NULL; 505 delete m_data_64; 506 m_data_64 = NULL; 507 } 508 509 lldb::addr_t 510 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetDataAddress () 511 { 512 if (!m_data_32 && !m_data_64) 513 return LLDB_INVALID_ADDRESS; 514 return m_data_32 ? m_data_32->_data : 515 m_data_64->_data; 516 } 517 518 uint64_t 519 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetUsedCount () 520 { 521 if (!m_data_32 && !m_data_64) 522 return 0; 523 return m_data_32 ? m_data_32->_used : 524 m_data_64->_used; 525 } 526 527 uint64_t 528 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetOffset () 529 { 530 if (!m_data_32 && !m_data_64) 531 return 0; 532 return m_data_32 ? m_data_32->_offset : 533 m_data_64->_offset; 534 } 535 536 uint64_t 537 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize () 538 { 539 if (!m_data_32 && !m_data_64) 540 return 0; 541 return m_data_32 ? m_data_32->_size : 542 m_data_64->_size; 543 } 544 545 lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 546 SyntheticChildrenFrontEnd (*valobj_sp.get()), 547 m_exe_ctx_ref (), 548 m_ptr_size (8), 549 m_items (0), 550 m_data_ptr (0) 551 { 552 if (valobj_sp) 553 { 554 CompilerType type = valobj_sp->GetCompilerType(); 555 if (type) 556 { 557 ClangASTContext *ast = valobj_sp->GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext(); 558 if (ast) 559 m_id_type = CompilerType(ast->getASTContext(), ast->getASTContext()->ObjCBuiltinIdTy); 560 } 561 } 562 } 563 564 size_t 565 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 566 { 567 const char* item_name = name.GetCString(); 568 uint32_t idx = ExtractIndexFromString(item_name); 569 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 570 return UINT32_MAX; 571 return idx; 572 } 573 574 size_t 575 lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren () 576 { 577 return m_items; 578 } 579 580 bool 581 lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() 582 { 583 m_ptr_size = 0; 584 m_items = 0; 585 m_data_ptr = 0; 586 m_children.clear(); 587 ValueObjectSP valobj_sp = m_backend.GetSP(); 588 if (!valobj_sp) 589 return false; 590 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 591 Error error; 592 error.Clear(); 593 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 594 if (!process_sp) 595 return false; 596 m_ptr_size = process_sp->GetAddressByteSize(); 597 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 598 m_items = process_sp->ReadPointerFromMemory(data_location, error); 599 if (error.Fail()) 600 return false; 601 m_data_ptr = data_location+m_ptr_size; 602 return false; 603 } 604 605 bool 606 lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren () 607 { 608 return true; 609 } 610 611 lldb::ValueObjectSP 612 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx) 613 { 614 if (idx >= CalculateNumChildren()) 615 return lldb::ValueObjectSP(); 616 lldb::addr_t object_at_idx = m_data_ptr; 617 object_at_idx += (idx * m_ptr_size); 618 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 619 if (!process_sp) 620 return lldb::ValueObjectSP(); 621 Error error; 622 if (error.Fail()) 623 return lldb::ValueObjectSP(); 624 StreamString idx_name; 625 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 626 lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(), 627 object_at_idx, 628 m_exe_ctx_ref, 629 m_id_type); 630 m_children.push_back(retval_sp); 631 return retval_sp; 632 } 633 634 lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 635 SyntheticChildrenFrontEnd (*valobj_sp.get()) 636 { 637 } 638 639 size_t 640 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 641 { 642 return UINT32_MAX; 643 } 644 645 size_t 646 lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren () 647 { 648 return 0; 649 } 650 651 bool 652 lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() 653 { 654 return false; 655 } 656 657 bool 658 lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren () 659 { 660 return false; 661 } 662 663 lldb::ValueObjectSP 664 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex (size_t idx) 665 { 666 return lldb::ValueObjectSP(); 667 } 668 669 SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 670 { 671 if (!valobj_sp) 672 return nullptr; 673 674 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP()); 675 if (!process_sp) 676 return NULL; 677 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime()); 678 if (!runtime) 679 return NULL; 680 681 CompilerType valobj_type(valobj_sp->GetCompilerType()); 682 Flags flags(valobj_type.GetTypeInfo()); 683 684 if (flags.IsClear(eTypeIsPointer)) 685 { 686 Error error; 687 valobj_sp = valobj_sp->AddressOf(error); 688 if (error.Fail() || !valobj_sp) 689 return NULL; 690 } 691 692 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get())); 693 694 if (!descriptor.get() || !descriptor->IsValid()) 695 return NULL; 696 697 const char* class_name = descriptor->GetClassName().GetCString(); 698 699 if (!class_name || !*class_name) 700 return NULL; 701 702 if (!strcmp(class_name,"__NSArrayI")) 703 { 704 return (new NSArrayISyntheticFrontEnd(valobj_sp)); 705 } 706 else if (!strcmp(class_name,"__NSArray0")) 707 { 708 return (new NSArray0SyntheticFrontEnd(valobj_sp)); 709 } 710 else if (!strcmp(class_name,"__NSArrayM")) 711 { 712 if (runtime->GetFoundationVersion() >= 1100) 713 return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp)); 714 else 715 return (new NSArrayMSyntheticFrontEnd_109(valobj_sp)); 716 } 717 718 return nullptr; 719 } 720