1 //===-- Cocoa.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 // Project includes 14 #include "Cocoa.h" 15 16 #include "lldb/Core/DataBufferHeap.h" 17 #include "lldb/Core/Error.h" 18 #include "lldb/Core/Mangled.h" 19 #include "lldb/Core/Stream.h" 20 #include "lldb/Core/ValueObject.h" 21 #include "lldb/Core/ValueObjectConstResult.h" 22 #include "lldb/DataFormatters/FormattersHelpers.h" 23 #include "lldb/DataFormatters/StringPrinter.h" 24 #include "lldb/DataFormatters/TypeSummary.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 "lldb/Target/Target.h" 30 #include "lldb/Target/Process.h" 31 #include "lldb/Utility/ProcessStructReader.h" 32 33 #include "NSString.h" 34 35 using namespace lldb; 36 using namespace lldb_private; 37 using namespace lldb_private::formatters; 38 39 bool 40 lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 41 { 42 ProcessSP process_sp = valobj.GetProcessSP(); 43 if (!process_sp) 44 return false; 45 46 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 47 48 if (!runtime) 49 return false; 50 51 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 52 53 if (!descriptor || !descriptor->IsValid()) 54 return false; 55 56 uint32_t ptr_size = process_sp->GetAddressByteSize(); 57 58 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 59 60 if (!valobj_addr) 61 return false; 62 63 const char* class_name = descriptor->GetClassName().GetCString(); 64 65 if (!class_name || !*class_name) 66 return false; 67 68 if (!strcmp(class_name,"NSBundle")) 69 { 70 uint64_t offset = 5 * ptr_size; 71 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true)); 72 73 StreamString summary_stream; 74 bool was_nsstring_ok = NSStringSummaryProvider(*text, summary_stream, options); 75 if (was_nsstring_ok && summary_stream.GetSize() > 0) 76 { 77 stream.Printf("%s",summary_stream.GetData()); 78 return true; 79 } 80 } 81 82 return false; 83 } 84 85 bool 86 lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 87 { 88 ProcessSP process_sp = valobj.GetProcessSP(); 89 if (!process_sp) 90 return false; 91 92 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 93 94 if (!runtime) 95 return false; 96 97 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 98 99 if (!descriptor || !descriptor->IsValid()) 100 return false; 101 102 uint32_t ptr_size = process_sp->GetAddressByteSize(); 103 104 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 105 106 if (!valobj_addr) 107 return false; 108 109 const char* class_name = descriptor->GetClassName().GetCString(); 110 111 if (!class_name || !*class_name) 112 return false; 113 114 if (!strcmp(class_name,"__NSTimeZone")) 115 { 116 uint64_t offset = ptr_size; 117 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType(), true)); 118 StreamString summary_stream; 119 bool was_nsstring_ok = NSStringSummaryProvider(*text, summary_stream, options); 120 if (was_nsstring_ok && summary_stream.GetSize() > 0) 121 { 122 stream.Printf("%s",summary_stream.GetData()); 123 return true; 124 } 125 } 126 127 return false; 128 } 129 130 bool 131 lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 132 { 133 ProcessSP process_sp = valobj.GetProcessSP(); 134 if (!process_sp) 135 return false; 136 137 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 138 139 if (!runtime) 140 return false; 141 142 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 143 144 if (!descriptor || !descriptor->IsValid()) 145 return false; 146 147 uint32_t ptr_size = process_sp->GetAddressByteSize(); 148 149 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 150 151 if (!valobj_addr) 152 return false; 153 154 const char* class_name = descriptor->GetClassName().GetCString(); 155 156 if (!class_name || !*class_name) 157 return false; 158 159 if (!strcmp(class_name,"NSConcreteNotification")) 160 { 161 uint64_t offset = ptr_size; 162 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType(), true)); 163 StreamString summary_stream; 164 bool was_nsstring_ok = NSStringSummaryProvider(*text, summary_stream, options); 165 if (was_nsstring_ok && summary_stream.GetSize() > 0) 166 { 167 stream.Printf("%s",summary_stream.GetData()); 168 return true; 169 } 170 } 171 172 return false; 173 } 174 175 bool 176 lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 177 { 178 ProcessSP process_sp = valobj.GetProcessSP(); 179 if (!process_sp) 180 return false; 181 182 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 183 184 if (!runtime) 185 return false; 186 187 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 188 189 if (!descriptor || !descriptor->IsValid()) 190 return false; 191 192 uint32_t ptr_size = process_sp->GetAddressByteSize(); 193 194 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 195 196 if (!valobj_addr) 197 return false; 198 199 const char* class_name = descriptor->GetClassName().GetCString(); 200 201 if (!class_name || !*class_name) 202 return false; 203 204 uint64_t port_number = 0; 205 206 if (!strcmp(class_name,"NSMachPort")) 207 { 208 uint64_t offset = (ptr_size == 4 ? 12 : 20); 209 Error error; 210 port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error); 211 if (error.Success()) 212 { 213 stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF)); 214 return true; 215 } 216 } 217 218 return false; 219 } 220 221 bool 222 lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 223 { 224 ProcessSP process_sp = valobj.GetProcessSP(); 225 if (!process_sp) 226 return false; 227 228 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 229 230 if (!runtime) 231 return false; 232 233 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 234 235 if (!descriptor || !descriptor->IsValid()) 236 return false; 237 238 uint32_t ptr_size = process_sp->GetAddressByteSize(); 239 240 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 241 242 if (!valobj_addr) 243 return false; 244 245 const char* class_name = descriptor->GetClassName().GetCString(); 246 247 if (!class_name || !*class_name) 248 return false; 249 250 uint64_t count = 0; 251 252 do { 253 if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet")) 254 { 255 Error error; 256 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error); 257 if (error.Fail()) 258 return false; 259 // this means the set is empty - count = 0 260 if ((mode & 1) == 1) 261 { 262 count = 0; 263 break; 264 } 265 if ((mode & 2) == 2) 266 mode = 1; // this means the set only has one range 267 else 268 mode = 2; // this means the set has multiple ranges 269 if (mode == 1) 270 { 271 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error); 272 if (error.Fail()) 273 return false; 274 } 275 else 276 { 277 // read a pointer to the data at 2*ptr_size 278 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error); 279 if (error.Fail()) 280 return false; 281 // read the data at 2*ptr_size from the first location 282 count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error); 283 if (error.Fail()) 284 return false; 285 } 286 } 287 else 288 return false; 289 } while (false); 290 stream.Printf("%" PRIu64 " index%s", 291 count, 292 (count == 1 ? "" : "es")); 293 return true; 294 } 295 296 static void 297 NSNumber_FormatChar (ValueObject& valobj, 298 Stream& stream, 299 char value, 300 lldb::LanguageType lang) 301 { 302 static ConstString g_TypeHint("NSNumber:char"); 303 304 std::string prefix,suffix; 305 if (Language* language = Language::FindPlugin(lang)) 306 { 307 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix)) 308 { 309 prefix.clear(); 310 suffix.clear(); 311 } 312 } 313 314 stream.Printf("%s%hhd%s", 315 prefix.c_str(), 316 value, 317 suffix.c_str()); 318 } 319 320 static void 321 NSNumber_FormatShort (ValueObject& valobj, 322 Stream& stream, 323 short value, 324 lldb::LanguageType lang) 325 { 326 static ConstString g_TypeHint("NSNumber:short"); 327 328 std::string prefix,suffix; 329 if (Language* language = Language::FindPlugin(lang)) 330 { 331 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix)) 332 { 333 prefix.clear(); 334 suffix.clear(); 335 } 336 } 337 338 stream.Printf("%s%hd%s", 339 prefix.c_str(), 340 value, 341 suffix.c_str()); 342 } 343 344 static void 345 NSNumber_FormatInt (ValueObject& valobj, 346 Stream& stream, 347 int value, 348 lldb::LanguageType lang) 349 { 350 static ConstString g_TypeHint("NSNumber:int"); 351 352 std::string prefix,suffix; 353 if (Language* language = Language::FindPlugin(lang)) 354 { 355 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix)) 356 { 357 prefix.clear(); 358 suffix.clear(); 359 } 360 } 361 362 stream.Printf("%s%d%s", 363 prefix.c_str(), 364 value, 365 suffix.c_str()); 366 } 367 368 static void 369 NSNumber_FormatLong (ValueObject& valobj, 370 Stream& stream, 371 uint64_t value, 372 lldb::LanguageType lang) 373 { 374 static ConstString g_TypeHint("NSNumber:long"); 375 376 std::string prefix,suffix; 377 if (Language* language = Language::FindPlugin(lang)) 378 { 379 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix)) 380 { 381 prefix.clear(); 382 suffix.clear(); 383 } 384 } 385 386 stream.Printf("%s%" PRId64 "%s", 387 prefix.c_str(), 388 value, 389 suffix.c_str()); 390 } 391 392 static void 393 NSNumber_FormatFloat (ValueObject& valobj, 394 Stream& stream, 395 float value, 396 lldb::LanguageType lang) 397 { 398 static ConstString g_TypeHint("NSNumber:float"); 399 400 std::string prefix,suffix; 401 if (Language* language = Language::FindPlugin(lang)) 402 { 403 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix)) 404 { 405 prefix.clear(); 406 suffix.clear(); 407 } 408 } 409 410 stream.Printf("%s%f%s", 411 prefix.c_str(), 412 value, 413 suffix.c_str()); 414 } 415 416 static void 417 NSNumber_FormatDouble (ValueObject& valobj, 418 Stream& stream, 419 double value, 420 lldb::LanguageType lang) 421 { 422 static ConstString g_TypeHint("NSNumber:double"); 423 424 std::string prefix,suffix; 425 if (Language* language = Language::FindPlugin(lang)) 426 { 427 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix)) 428 { 429 prefix.clear(); 430 suffix.clear(); 431 } 432 } 433 434 stream.Printf("%s%g%s", 435 prefix.c_str(), 436 value, 437 suffix.c_str()); 438 } 439 440 bool 441 lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 442 { 443 ProcessSP process_sp = valobj.GetProcessSP(); 444 if (!process_sp) 445 return false; 446 447 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 448 449 if (!runtime) 450 return false; 451 452 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 453 454 if (!descriptor || !descriptor->IsValid()) 455 return false; 456 457 uint32_t ptr_size = process_sp->GetAddressByteSize(); 458 459 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 460 461 if (!valobj_addr) 462 return false; 463 464 const char* class_name = descriptor->GetClassName().GetCString(); 465 466 if (!class_name || !*class_name) 467 return false; 468 469 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber")) 470 { 471 uint64_t value = 0; 472 uint64_t i_bits = 0; 473 if (descriptor->GetTaggedPointerInfo(&i_bits,&value)) 474 { 475 switch (i_bits) 476 { 477 case 0: 478 NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage()); 479 break; 480 case 1: 481 case 4: 482 NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage()); 483 break; 484 case 2: 485 case 8: 486 NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage()); 487 break; 488 case 3: 489 case 12: 490 NSNumber_FormatLong(valobj, stream, value, options.GetLanguage()); 491 break; 492 default: 493 return false; 494 } 495 return true; 496 } 497 else 498 { 499 Error error; 500 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F); 501 uint64_t data_location = valobj_addr + 2*ptr_size; 502 uint64_t value = 0; 503 if (error.Fail()) 504 return false; 505 switch (data_type) 506 { 507 case 1: // 0B00001 508 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error); 509 if (error.Fail()) 510 return false; 511 NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage()); 512 break; 513 case 2: // 0B0010 514 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error); 515 if (error.Fail()) 516 return false; 517 NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage()); 518 break; 519 case 3: // 0B0011 520 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 521 if (error.Fail()) 522 return false; 523 NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage()); 524 break; 525 case 17: // 0B10001 526 data_location += 8; 527 LLVM_FALLTHROUGH; 528 case 4: // 0B0100 529 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 530 if (error.Fail()) 531 return false; 532 NSNumber_FormatLong(valobj, stream, value, options.GetLanguage()); 533 break; 534 case 5: // 0B0101 535 { 536 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 537 if (error.Fail()) 538 return false; 539 float flt_value = *((float*)&flt_as_int); 540 NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage()); 541 break; 542 } 543 case 6: // 0B0110 544 { 545 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 546 if (error.Fail()) 547 return false; 548 double dbl_value = *((double*)&dbl_as_lng); 549 NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage()); 550 break; 551 } 552 default: 553 return false; 554 } 555 return true; 556 } 557 } 558 559 return false; 560 } 561 562 bool 563 lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 564 { 565 ProcessSP process_sp = valobj.GetProcessSP(); 566 if (!process_sp) 567 return false; 568 569 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 570 571 if (!runtime) 572 return false; 573 574 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 575 576 if (!descriptor || !descriptor->IsValid()) 577 return false; 578 579 uint32_t ptr_size = process_sp->GetAddressByteSize(); 580 581 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 582 583 if (!valobj_addr) 584 return false; 585 586 const char* class_name = descriptor->GetClassName().GetCString(); 587 588 if (!class_name || !*class_name) 589 return false; 590 591 if (strcmp(class_name, "NSURL") == 0) 592 { 593 uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit) 594 uint64_t offset_base = offset_text + ptr_size; 595 CompilerType type(valobj.GetCompilerType()); 596 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true)); 597 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true)); 598 if (!text) 599 return false; 600 if (text->GetValueAsUnsigned(0) == 0) 601 return false; 602 StreamString summary; 603 if (!NSStringSummaryProvider(*text, summary, options)) 604 return false; 605 if (base && base->GetValueAsUnsigned(0)) 606 { 607 if (summary.GetSize() > 0) 608 summary.GetString().resize(summary.GetSize()-1); 609 summary.Printf(" -- "); 610 StreamString base_summary; 611 if (NSURLSummaryProvider(*base, base_summary, options) && base_summary.GetSize() > 0) 612 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData()); 613 } 614 if (summary.GetSize()) 615 { 616 stream.Printf("%s",summary.GetData()); 617 return true; 618 } 619 } 620 621 return false; 622 } 623 624 bool 625 lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 626 { 627 ProcessSP process_sp = valobj.GetProcessSP(); 628 if (!process_sp) 629 return false; 630 631 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 632 633 if (!runtime) 634 return false; 635 636 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 637 638 if (!descriptor || !descriptor->IsValid()) 639 return false; 640 641 uint32_t ptr_size = process_sp->GetAddressByteSize(); 642 643 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 644 645 if (!valobj_addr) 646 return false; 647 648 uint64_t date_value_bits = 0; 649 double date_value = 0.0; 650 651 ConstString class_name = descriptor->GetClassName(); 652 653 static const ConstString g_NSDate("NSDate"); 654 static const ConstString g___NSDate("__NSDate"); 655 static const ConstString g___NSTaggedDate("__NSTaggedDate"); 656 static const ConstString g_NSCalendarDate("NSCalendarDate"); 657 658 if (class_name.IsEmpty()) 659 return false; 660 661 if ((class_name == g_NSDate) || 662 (class_name == g___NSDate) || 663 (class_name == g___NSTaggedDate)) 664 { 665 uint64_t info_bits=0,value_bits = 0; 666 if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits)) 667 { 668 date_value_bits = ((value_bits << 8) | (info_bits << 4)); 669 date_value = *((double*)&date_value_bits); 670 } 671 else 672 { 673 Error error; 674 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error); 675 date_value = *((double*)&date_value_bits); 676 if (error.Fail()) 677 return false; 678 } 679 } 680 else if (class_name == g_NSCalendarDate) 681 { 682 Error error; 683 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error); 684 date_value = *((double*)&date_value_bits); 685 if (error.Fail()) 686 return false; 687 } 688 else 689 return false; 690 691 if (date_value == -63114076800) 692 { 693 stream.Printf("0001-12-30 00:00:00 +0000"); 694 return true; 695 } 696 // this snippet of code assumes that time_t == seconds since Jan-1-1970 697 // this is generally true and POSIXly happy, but might break if a library 698 // vendor decides to get creative 699 time_t epoch = GetOSXEpoch(); 700 epoch = epoch + (time_t)date_value; 701 tm *tm_date = gmtime(&epoch); 702 if (!tm_date) 703 return false; 704 std::string buffer(1024,0); 705 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0) 706 return false; 707 stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str()); 708 return true; 709 } 710 711 bool 712 lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 713 { 714 ProcessSP process_sp = valobj.GetProcessSP(); 715 if (!process_sp) 716 return false; 717 718 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 719 720 if (!runtime) 721 return false; 722 723 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0))); 724 725 if (!descriptor || !descriptor->IsValid()) 726 return false; 727 728 ConstString class_name = descriptor->GetClassName(); 729 730 if (class_name.IsEmpty()) 731 return false; 732 733 if (ConstString cs = Mangled(class_name).GetDemangledName(lldb::eLanguageTypeUnknown)) 734 class_name = cs; 735 736 stream.Printf("%s",class_name.AsCString("<unknown class>")); 737 return true; 738 } 739 740 class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd 741 { 742 public: 743 ObjCClassSyntheticChildrenFrontEnd (lldb::ValueObjectSP valobj_sp) : 744 SyntheticChildrenFrontEnd(*valobj_sp) 745 { 746 } 747 748 ~ObjCClassSyntheticChildrenFrontEnd() override = default; 749 750 size_t 751 CalculateNumChildren() override 752 { 753 return 0; 754 } 755 756 lldb::ValueObjectSP 757 GetChildAtIndex(size_t idx) override 758 { 759 return lldb::ValueObjectSP(); 760 } 761 762 bool 763 Update() override 764 { 765 return false; 766 } 767 768 bool 769 MightHaveChildren() override 770 { 771 return false; 772 } 773 774 size_t 775 GetIndexOfChildWithName(const ConstString &name) override 776 { 777 return UINT32_MAX; 778 } 779 }; 780 781 SyntheticChildrenFrontEnd* 782 lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 783 { 784 return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp); 785 } 786 787 template<bool needs_at> 788 bool 789 lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 790 { 791 ProcessSP process_sp = valobj.GetProcessSP(); 792 if (!process_sp) 793 return false; 794 795 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 796 797 if (!runtime) 798 return false; 799 800 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 801 802 if (!descriptor || !descriptor->IsValid()) 803 return false; 804 805 bool is_64bit = (process_sp->GetAddressByteSize() == 8); 806 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 807 808 if (!valobj_addr) 809 return false; 810 811 uint64_t value = 0; 812 813 const char* class_name = descriptor->GetClassName().GetCString(); 814 815 if (!class_name || !*class_name) 816 return false; 817 818 if (!strcmp(class_name,"NSConcreteData") || 819 !strcmp(class_name,"NSConcreteMutableData") || 820 !strcmp(class_name,"__NSCFData")) 821 { 822 uint32_t offset = (is_64bit ? 16 : 8); 823 Error error; 824 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error); 825 if (error.Fail()) 826 return false; 827 } 828 else if (!strcmp(class_name, "_NSInlineData")) 829 { 830 uint32_t offset = (is_64bit ? 8 : 4); 831 Error error; 832 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, 2, 0, error); 833 if (error.Fail()) 834 return false; 835 } 836 else if (!strcmp(class_name, "_NSZeroData")) 837 { 838 value = 0; 839 } 840 else 841 return false; 842 843 stream.Printf("%s%" PRIu64 " byte%s%s", 844 (needs_at ? "@\"" : ""), 845 value, 846 (value != 1 ? "s" : ""), 847 (needs_at ? "\"" : "")); 848 849 return true; 850 } 851 852 bool 853 lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 854 { 855 const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo(); 856 857 ValueObjectSP real_guy_sp = valobj.GetSP(); 858 859 if (type_info & eTypeIsPointer) 860 { 861 Error err; 862 real_guy_sp = valobj.Dereference(err); 863 if (err.Fail() || !real_guy_sp) 864 return false; 865 } 866 else if (type_info & eTypeIsReference) 867 { 868 real_guy_sp = valobj.GetChildAtIndex(0, true); 869 if (!real_guy_sp) 870 return false; 871 } 872 uint8_t value = (real_guy_sp->GetValueAsUnsigned(0) & 0xFF); 873 switch (value) 874 { 875 case 0: 876 stream.Printf("NO"); 877 break; 878 case 1: 879 stream.Printf("YES"); 880 break; 881 default: 882 stream.Printf("%u",value); 883 break; 884 } 885 return true; 886 } 887 888 template <bool is_sel_ptr> 889 bool 890 lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 891 { 892 lldb::ValueObjectSP valobj_sp; 893 894 CompilerType charstar (valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeChar).GetPointerType()); 895 896 if (!charstar) 897 return false; 898 899 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 900 901 if (is_sel_ptr) 902 { 903 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); 904 if (data_address == LLDB_INVALID_ADDRESS) 905 return false; 906 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar); 907 } 908 else 909 { 910 DataExtractor data; 911 Error error; 912 valobj.GetData(data, error); 913 if (error.Fail()) 914 return false; 915 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar); 916 } 917 918 if (!valobj_sp) 919 return false; 920 921 stream.Printf("%s",valobj_sp->GetSummaryAsCString()); 922 return true; 923 } 924 925 // POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001 926 // this call gives the POSIX equivalent of the Cocoa epoch 927 time_t 928 lldb_private::formatters::GetOSXEpoch () 929 { 930 static time_t epoch = 0; 931 if (!epoch) 932 { 933 #ifndef _WIN32 934 tzset(); 935 tm tm_epoch; 936 tm_epoch.tm_sec = 0; 937 tm_epoch.tm_hour = 0; 938 tm_epoch.tm_min = 0; 939 tm_epoch.tm_mon = 0; 940 tm_epoch.tm_mday = 1; 941 tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why. 942 tm_epoch.tm_isdst = -1; 943 tm_epoch.tm_gmtoff = 0; 944 tm_epoch.tm_zone = nullptr; 945 epoch = timegm(&tm_epoch); 946 #endif 947 } 948 return epoch; 949 } 950 951 template bool 952 lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&); 953 954 template bool 955 lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&); 956 957 template bool 958 lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&); 959 960 template bool 961 lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&); 962