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