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