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 = 0.0f; 540 memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int)); 541 NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage()); 542 break; 543 } 544 case 6: // 0B0110 545 { 546 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 547 if (error.Fail()) 548 return false; 549 double dbl_value = 0.0; 550 memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng)); 551 NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage()); 552 break; 553 } 554 default: 555 return false; 556 } 557 return true; 558 } 559 } 560 561 return false; 562 } 563 564 bool 565 lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 566 { 567 ProcessSP process_sp = valobj.GetProcessSP(); 568 if (!process_sp) 569 return false; 570 571 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 572 573 if (!runtime) 574 return false; 575 576 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 577 578 if (!descriptor || !descriptor->IsValid()) 579 return false; 580 581 uint32_t ptr_size = process_sp->GetAddressByteSize(); 582 583 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 584 585 if (!valobj_addr) 586 return false; 587 588 const char* class_name = descriptor->GetClassName().GetCString(); 589 590 if (!class_name || !*class_name) 591 return false; 592 593 if (strcmp(class_name, "NSURL") == 0) 594 { 595 uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit) 596 uint64_t offset_base = offset_text + ptr_size; 597 CompilerType type(valobj.GetCompilerType()); 598 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true)); 599 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true)); 600 if (!text) 601 return false; 602 if (text->GetValueAsUnsigned(0) == 0) 603 return false; 604 StreamString summary; 605 if (!NSStringSummaryProvider(*text, summary, options)) 606 return false; 607 if (base && base->GetValueAsUnsigned(0)) 608 { 609 if (summary.GetSize() > 0) 610 summary.GetString().resize(summary.GetSize()-1); 611 summary.Printf(" -- "); 612 StreamString base_summary; 613 if (NSURLSummaryProvider(*base, base_summary, options) && base_summary.GetSize() > 0) 614 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData()); 615 } 616 if (summary.GetSize()) 617 { 618 stream.Printf("%s",summary.GetData()); 619 return true; 620 } 621 } 622 623 return false; 624 } 625 626 bool 627 lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 628 { 629 ProcessSP process_sp = valobj.GetProcessSP(); 630 if (!process_sp) 631 return false; 632 633 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 634 635 if (!runtime) 636 return false; 637 638 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 639 640 if (!descriptor || !descriptor->IsValid()) 641 return false; 642 643 uint32_t ptr_size = process_sp->GetAddressByteSize(); 644 645 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 646 647 if (!valobj_addr) 648 return false; 649 650 uint64_t date_value_bits = 0; 651 double date_value = 0.0; 652 653 ConstString class_name = descriptor->GetClassName(); 654 655 static const ConstString g_NSDate("NSDate"); 656 static const ConstString g___NSDate("__NSDate"); 657 static const ConstString g___NSTaggedDate("__NSTaggedDate"); 658 static const ConstString g_NSCalendarDate("NSCalendarDate"); 659 660 if (class_name.IsEmpty()) 661 return false; 662 663 if ((class_name == g_NSDate) || 664 (class_name == g___NSDate) || 665 (class_name == g___NSTaggedDate)) 666 { 667 uint64_t info_bits=0,value_bits = 0; 668 if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits)) 669 { 670 date_value_bits = ((value_bits << 8) | (info_bits << 4)); 671 memcpy(&date_value, &date_value_bits, sizeof(date_value_bits)); 672 } 673 else 674 { 675 llvm::Triple triple(process_sp->GetTarget().GetArchitecture().GetTriple()); 676 uint32_t delta = (triple.isWatchOS() && triple.isWatchABI()) ? 8 : ptr_size; 677 Error error; 678 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+delta, 8, 0, error); 679 memcpy(&date_value, &date_value_bits, sizeof(date_value_bits)); 680 if (error.Fail()) 681 return false; 682 } 683 } 684 else if (class_name == g_NSCalendarDate) 685 { 686 Error error; 687 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error); 688 memcpy(&date_value, &date_value_bits, sizeof(date_value_bits)); 689 if (error.Fail()) 690 return false; 691 } 692 else 693 return false; 694 695 if (date_value == -63114076800) 696 { 697 stream.Printf("0001-12-30 00:00:00 +0000"); 698 return true; 699 } 700 // this snippet of code assumes that time_t == seconds since Jan-1-1970 701 // this is generally true and POSIXly happy, but might break if a library 702 // vendor decides to get creative 703 time_t epoch = GetOSXEpoch(); 704 epoch = epoch + (time_t)date_value; 705 tm *tm_date = gmtime(&epoch); 706 if (!tm_date) 707 return false; 708 std::string buffer(1024,0); 709 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0) 710 return false; 711 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()); 712 return true; 713 } 714 715 bool 716 lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 717 { 718 ProcessSP process_sp = valobj.GetProcessSP(); 719 if (!process_sp) 720 return false; 721 722 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 723 724 if (!runtime) 725 return false; 726 727 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0))); 728 729 if (!descriptor || !descriptor->IsValid()) 730 return false; 731 732 ConstString class_name = descriptor->GetClassName(); 733 734 if (class_name.IsEmpty()) 735 return false; 736 737 if (ConstString cs = Mangled(class_name).GetDemangledName(lldb::eLanguageTypeUnknown)) 738 class_name = cs; 739 740 stream.Printf("%s",class_name.AsCString("<unknown class>")); 741 return true; 742 } 743 744 class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd 745 { 746 public: 747 ObjCClassSyntheticChildrenFrontEnd (lldb::ValueObjectSP valobj_sp) : 748 SyntheticChildrenFrontEnd(*valobj_sp) 749 { 750 } 751 752 ~ObjCClassSyntheticChildrenFrontEnd() override = default; 753 754 size_t 755 CalculateNumChildren() override 756 { 757 return 0; 758 } 759 760 lldb::ValueObjectSP 761 GetChildAtIndex(size_t idx) override 762 { 763 return lldb::ValueObjectSP(); 764 } 765 766 bool 767 Update() override 768 { 769 return false; 770 } 771 772 bool 773 MightHaveChildren() override 774 { 775 return false; 776 } 777 778 size_t 779 GetIndexOfChildWithName(const ConstString &name) override 780 { 781 return UINT32_MAX; 782 } 783 }; 784 785 SyntheticChildrenFrontEnd* 786 lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 787 { 788 return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp); 789 } 790 791 template<bool needs_at> 792 bool 793 lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 794 { 795 ProcessSP process_sp = valobj.GetProcessSP(); 796 if (!process_sp) 797 return false; 798 799 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 800 801 if (!runtime) 802 return false; 803 804 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 805 806 if (!descriptor || !descriptor->IsValid()) 807 return false; 808 809 bool is_64bit = (process_sp->GetAddressByteSize() == 8); 810 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 811 812 if (!valobj_addr) 813 return false; 814 815 uint64_t value = 0; 816 817 const char* class_name = descriptor->GetClassName().GetCString(); 818 819 if (!class_name || !*class_name) 820 return false; 821 822 if (!strcmp(class_name,"NSConcreteData") || 823 !strcmp(class_name,"NSConcreteMutableData") || 824 !strcmp(class_name,"__NSCFData")) 825 { 826 uint32_t offset = (is_64bit ? 16 : 8); 827 Error error; 828 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error); 829 if (error.Fail()) 830 return false; 831 } 832 else if (!strcmp(class_name, "_NSInlineData")) 833 { 834 uint32_t offset = (is_64bit ? 8 : 4); 835 Error error; 836 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, 2, 0, error); 837 if (error.Fail()) 838 return false; 839 } 840 else if (!strcmp(class_name, "_NSZeroData")) 841 { 842 value = 0; 843 } 844 else 845 return false; 846 847 stream.Printf("%s%" PRIu64 " byte%s%s", 848 (needs_at ? "@\"" : ""), 849 value, 850 (value != 1 ? "s" : ""), 851 (needs_at ? "\"" : "")); 852 853 return true; 854 } 855 856 bool 857 lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 858 { 859 const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo(); 860 861 ValueObjectSP real_guy_sp = valobj.GetSP(); 862 863 if (type_info & eTypeIsPointer) 864 { 865 Error err; 866 real_guy_sp = valobj.Dereference(err); 867 if (err.Fail() || !real_guy_sp) 868 return false; 869 } 870 else if (type_info & eTypeIsReference) 871 { 872 real_guy_sp = valobj.GetChildAtIndex(0, true); 873 if (!real_guy_sp) 874 return false; 875 } 876 uint8_t value = (real_guy_sp->GetValueAsUnsigned(0) & 0xFF); 877 switch (value) 878 { 879 case 0: 880 stream.Printf("NO"); 881 break; 882 case 1: 883 stream.Printf("YES"); 884 break; 885 default: 886 stream.Printf("%u",value); 887 break; 888 } 889 return true; 890 } 891 892 template <bool is_sel_ptr> 893 bool 894 lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 895 { 896 lldb::ValueObjectSP valobj_sp; 897 898 CompilerType charstar (valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeChar).GetPointerType()); 899 900 if (!charstar) 901 return false; 902 903 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 904 905 if (is_sel_ptr) 906 { 907 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); 908 if (data_address == LLDB_INVALID_ADDRESS) 909 return false; 910 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar); 911 } 912 else 913 { 914 DataExtractor data; 915 Error error; 916 valobj.GetData(data, error); 917 if (error.Fail()) 918 return false; 919 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar); 920 } 921 922 if (!valobj_sp) 923 return false; 924 925 stream.Printf("%s",valobj_sp->GetSummaryAsCString()); 926 return true; 927 } 928 929 // POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001 930 // this call gives the POSIX equivalent of the Cocoa epoch 931 time_t 932 lldb_private::formatters::GetOSXEpoch () 933 { 934 static time_t epoch = 0; 935 if (!epoch) 936 { 937 #ifndef _WIN32 938 tzset(); 939 tm tm_epoch; 940 tm_epoch.tm_sec = 0; 941 tm_epoch.tm_hour = 0; 942 tm_epoch.tm_min = 0; 943 tm_epoch.tm_mon = 0; 944 tm_epoch.tm_mday = 1; 945 tm_epoch.tm_year = 2001-1900; 946 tm_epoch.tm_isdst = -1; 947 tm_epoch.tm_gmtoff = 0; 948 tm_epoch.tm_zone = nullptr; 949 epoch = timegm(&tm_epoch); 950 #endif 951 } 952 return epoch; 953 } 954 955 template bool 956 lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&); 957 958 template bool 959 lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&); 960 961 template bool 962 lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&); 963 964 template bool 965 lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&); 966