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