1254721Semaste//===-- Cocoa.cpp -------------------------------------------------*- C++ -*-===// 2254721Semaste// 3254721Semaste// The LLVM Compiler Infrastructure 4254721Semaste// 5254721Semaste// This file is distributed under the University of Illinois Open Source 6254721Semaste// License. See LICENSE.TXT for details. 7254721Semaste// 8254721Semaste//===----------------------------------------------------------------------===// 9254721Semaste 10254721Semaste#include "lldb/lldb-python.h" 11254721Semaste 12254721Semaste#include "lldb/DataFormatters/CXXFormatterFunctions.h" 13254721Semaste 14254721Semaste#include "lldb/Core/DataBufferHeap.h" 15254721Semaste#include "lldb/Core/Error.h" 16254721Semaste#include "lldb/Core/Stream.h" 17254721Semaste#include "lldb/Core/ValueObject.h" 18254721Semaste#include "lldb/Core/ValueObjectConstResult.h" 19254721Semaste#include "lldb/Host/Endian.h" 20254721Semaste#include "lldb/Symbol/ClangASTContext.h" 21254721Semaste#include "lldb/Target/ObjCLanguageRuntime.h" 22254721Semaste#include "lldb/Target/Target.h" 23254721Semaste 24254721Semasteusing namespace lldb; 25254721Semasteusing namespace lldb_private; 26254721Semasteusing namespace lldb_private::formatters; 27254721Semaste 28254721Semastebool 29254721Semastelldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream) 30254721Semaste{ 31254721Semaste ProcessSP process_sp = valobj.GetProcessSP(); 32254721Semaste if (!process_sp) 33254721Semaste return false; 34254721Semaste 35254721Semaste ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 36254721Semaste 37254721Semaste if (!runtime) 38254721Semaste return false; 39254721Semaste 40254721Semaste ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 41254721Semaste 42254721Semaste if (!descriptor.get() || !descriptor->IsValid()) 43254721Semaste return false; 44254721Semaste 45254721Semaste uint32_t ptr_size = process_sp->GetAddressByteSize(); 46254721Semaste 47254721Semaste lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 48254721Semaste 49254721Semaste if (!valobj_addr) 50254721Semaste return false; 51254721Semaste 52254721Semaste const char* class_name = descriptor->GetClassName().GetCString(); 53254721Semaste 54254721Semaste if (!class_name || !*class_name) 55254721Semaste return false; 56254721Semaste 57254721Semaste if (!strcmp(class_name,"NSBundle")) 58254721Semaste { 59254721Semaste uint64_t offset = 5 * ptr_size; 60254721Semaste ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true)); 61254721Semaste 62254721Semaste StreamString summary_stream; 63254721Semaste bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); 64254721Semaste if (was_nsstring_ok && summary_stream.GetSize() > 0) 65254721Semaste { 66254721Semaste stream.Printf("%s",summary_stream.GetData()); 67254721Semaste return true; 68254721Semaste } 69254721Semaste } 70254721Semaste // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle] 71254721Semaste // which is encoded differently and needs to be handled by running code 72254721Semaste return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream); 73254721Semaste} 74254721Semaste 75254721Semastebool 76254721Semastelldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream) 77254721Semaste{ 78254721Semaste ProcessSP process_sp = valobj.GetProcessSP(); 79254721Semaste if (!process_sp) 80254721Semaste return false; 81254721Semaste 82254721Semaste ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 83254721Semaste 84254721Semaste if (!runtime) 85254721Semaste return false; 86254721Semaste 87254721Semaste ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 88254721Semaste 89254721Semaste if (!descriptor.get() || !descriptor->IsValid()) 90254721Semaste return false; 91254721Semaste 92254721Semaste uint32_t ptr_size = process_sp->GetAddressByteSize(); 93254721Semaste 94254721Semaste lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 95254721Semaste 96254721Semaste if (!valobj_addr) 97254721Semaste return false; 98254721Semaste 99254721Semaste const char* class_name = descriptor->GetClassName().GetCString(); 100254721Semaste 101254721Semaste if (!class_name || !*class_name) 102254721Semaste return false; 103254721Semaste 104254721Semaste if (!strcmp(class_name,"__NSTimeZone")) 105254721Semaste { 106254721Semaste uint64_t offset = ptr_size; 107254721Semaste ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true)); 108254721Semaste StreamString summary_stream; 109254721Semaste bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); 110254721Semaste if (was_nsstring_ok && summary_stream.GetSize() > 0) 111254721Semaste { 112254721Semaste stream.Printf("%s",summary_stream.GetData()); 113254721Semaste return true; 114254721Semaste } 115254721Semaste } 116254721Semaste return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream); 117254721Semaste} 118254721Semaste 119254721Semastebool 120254721Semastelldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream) 121254721Semaste{ 122254721Semaste ProcessSP process_sp = valobj.GetProcessSP(); 123254721Semaste if (!process_sp) 124254721Semaste return false; 125254721Semaste 126254721Semaste ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 127254721Semaste 128254721Semaste if (!runtime) 129254721Semaste return false; 130254721Semaste 131254721Semaste ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 132254721Semaste 133254721Semaste if (!descriptor.get() || !descriptor->IsValid()) 134254721Semaste return false; 135254721Semaste 136254721Semaste uint32_t ptr_size = process_sp->GetAddressByteSize(); 137254721Semaste 138254721Semaste lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 139254721Semaste 140254721Semaste if (!valobj_addr) 141254721Semaste return false; 142254721Semaste 143254721Semaste const char* class_name = descriptor->GetClassName().GetCString(); 144254721Semaste 145254721Semaste if (!class_name || !*class_name) 146254721Semaste return false; 147254721Semaste 148254721Semaste if (!strcmp(class_name,"NSConcreteNotification")) 149254721Semaste { 150254721Semaste uint64_t offset = ptr_size; 151254721Semaste ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true)); 152254721Semaste StreamString summary_stream; 153254721Semaste bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); 154254721Semaste if (was_nsstring_ok && summary_stream.GetSize() > 0) 155254721Semaste { 156254721Semaste stream.Printf("%s",summary_stream.GetData()); 157254721Semaste return true; 158254721Semaste } 159254721Semaste } 160254721Semaste // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle] 161254721Semaste // which is encoded differently and needs to be handled by running code 162254721Semaste return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream); 163254721Semaste} 164254721Semaste 165254721Semastebool 166254721Semastelldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream) 167254721Semaste{ 168254721Semaste ProcessSP process_sp = valobj.GetProcessSP(); 169254721Semaste if (!process_sp) 170254721Semaste return false; 171254721Semaste 172254721Semaste ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 173254721Semaste 174254721Semaste if (!runtime) 175254721Semaste return false; 176254721Semaste 177254721Semaste ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 178254721Semaste 179254721Semaste if (!descriptor.get() || !descriptor->IsValid()) 180254721Semaste return false; 181254721Semaste 182254721Semaste uint32_t ptr_size = process_sp->GetAddressByteSize(); 183254721Semaste 184254721Semaste lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 185254721Semaste 186254721Semaste if (!valobj_addr) 187254721Semaste return false; 188254721Semaste 189254721Semaste const char* class_name = descriptor->GetClassName().GetCString(); 190254721Semaste 191254721Semaste if (!class_name || !*class_name) 192254721Semaste return false; 193254721Semaste 194254721Semaste uint64_t port_number = 0; 195254721Semaste 196254721Semaste do 197254721Semaste { 198254721Semaste if (!strcmp(class_name,"NSMachPort")) 199254721Semaste { 200254721Semaste uint64_t offset = (ptr_size == 4 ? 12 : 20); 201254721Semaste Error error; 202254721Semaste port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error); 203254721Semaste if (error.Success()) 204254721Semaste break; 205254721Semaste } 206254721Semaste if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number)) 207254721Semaste return false; 208254721Semaste } while (false); 209254721Semaste 210254721Semaste stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF)); 211254721Semaste return true; 212254721Semaste} 213254721Semaste 214254721Semastebool 215254721Semastelldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream) 216254721Semaste{ 217254721Semaste ProcessSP process_sp = valobj.GetProcessSP(); 218254721Semaste if (!process_sp) 219254721Semaste return false; 220254721Semaste 221254721Semaste ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 222254721Semaste 223254721Semaste if (!runtime) 224254721Semaste return false; 225254721Semaste 226254721Semaste ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 227254721Semaste 228254721Semaste if (!descriptor.get() || !descriptor->IsValid()) 229254721Semaste return false; 230254721Semaste 231254721Semaste uint32_t ptr_size = process_sp->GetAddressByteSize(); 232254721Semaste 233254721Semaste lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 234254721Semaste 235254721Semaste if (!valobj_addr) 236254721Semaste return false; 237254721Semaste 238254721Semaste const char* class_name = descriptor->GetClassName().GetCString(); 239254721Semaste 240254721Semaste if (!class_name || !*class_name) 241254721Semaste return false; 242254721Semaste 243254721Semaste uint64_t count = 0; 244254721Semaste 245254721Semaste do { 246254721Semaste if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet")) 247254721Semaste { 248254721Semaste Error error; 249254721Semaste uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error); 250254721Semaste if (error.Fail()) 251254721Semaste return false; 252254721Semaste // this means the set is empty - count = 0 253254721Semaste if ((mode & 1) == 1) 254254721Semaste { 255254721Semaste count = 0; 256254721Semaste break; 257254721Semaste } 258254721Semaste if ((mode & 2) == 2) 259254721Semaste mode = 1; // this means the set only has one range 260254721Semaste else 261254721Semaste mode = 2; // this means the set has multiple ranges 262254721Semaste if (mode == 1) 263254721Semaste { 264254721Semaste count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error); 265254721Semaste if (error.Fail()) 266254721Semaste return false; 267254721Semaste } 268254721Semaste else 269254721Semaste { 270254721Semaste // read a pointer to the data at 2*ptr_size 271254721Semaste count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error); 272254721Semaste if (error.Fail()) 273254721Semaste return false; 274254721Semaste // read the data at 2*ptr_size from the first location 275254721Semaste count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error); 276254721Semaste if (error.Fail()) 277254721Semaste return false; 278254721Semaste } 279254721Semaste } 280254721Semaste else 281254721Semaste { 282254721Semaste if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count)) 283254721Semaste return false; 284254721Semaste } 285254721Semaste } while (false); 286254721Semaste stream.Printf("%" PRIu64 " index%s", 287254721Semaste count, 288254721Semaste (count == 1 ? "" : "es")); 289254721Semaste return true; 290254721Semaste} 291254721Semaste 292254721Semastebool 293254721Semastelldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream) 294254721Semaste{ 295254721Semaste ProcessSP process_sp = valobj.GetProcessSP(); 296254721Semaste if (!process_sp) 297254721Semaste return false; 298254721Semaste 299254721Semaste ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 300254721Semaste 301254721Semaste if (!runtime) 302254721Semaste return false; 303254721Semaste 304254721Semaste ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 305254721Semaste 306254721Semaste if (!descriptor.get() || !descriptor->IsValid()) 307254721Semaste return false; 308254721Semaste 309254721Semaste uint32_t ptr_size = process_sp->GetAddressByteSize(); 310254721Semaste 311254721Semaste lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 312254721Semaste 313254721Semaste if (!valobj_addr) 314254721Semaste return false; 315254721Semaste 316254721Semaste const char* class_name = descriptor->GetClassName().GetCString(); 317254721Semaste 318254721Semaste if (!class_name || !*class_name) 319254721Semaste return false; 320254721Semaste 321254721Semaste if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber")) 322254721Semaste { 323254721Semaste uint64_t value = 0; 324254721Semaste uint64_t i_bits = 0; 325254721Semaste if (descriptor->GetTaggedPointerInfo(&i_bits,&value)) 326254721Semaste { 327254721Semaste switch (i_bits) 328254721Semaste { 329254721Semaste case 0: 330254721Semaste stream.Printf("(char)%hhd",(char)value); 331254721Semaste break; 332254721Semaste case 1: 333254721Semaste case 4: 334254721Semaste stream.Printf("(short)%hd",(short)value); 335254721Semaste break; 336254721Semaste case 2: 337254721Semaste case 8: 338254721Semaste stream.Printf("(int)%d",(int)value); 339254721Semaste break; 340254721Semaste case 3: 341254721Semaste case 12: 342254721Semaste stream.Printf("(long)%" PRId64,value); 343254721Semaste break; 344254721Semaste default: 345254721Semaste stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value); 346254721Semaste break; 347254721Semaste } 348254721Semaste return true; 349254721Semaste } 350254721Semaste else 351254721Semaste { 352254721Semaste Error error; 353254721Semaste uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F); 354254721Semaste uint64_t data_location = valobj_addr + 2*ptr_size; 355254721Semaste uint64_t value = 0; 356254721Semaste if (error.Fail()) 357254721Semaste return false; 358254721Semaste switch (data_type) 359254721Semaste { 360254721Semaste case 1: // 0B00001 361254721Semaste value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error); 362254721Semaste if (error.Fail()) 363254721Semaste return false; 364254721Semaste stream.Printf("(char)%hhd",(char)value); 365254721Semaste break; 366254721Semaste case 2: // 0B0010 367254721Semaste value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error); 368254721Semaste if (error.Fail()) 369254721Semaste return false; 370254721Semaste stream.Printf("(short)%hd",(short)value); 371254721Semaste break; 372254721Semaste case 3: // 0B0011 373254721Semaste value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 374254721Semaste if (error.Fail()) 375254721Semaste return false; 376254721Semaste stream.Printf("(int)%d",(int)value); 377254721Semaste break; 378254721Semaste case 17: // 0B10001 379254721Semaste data_location += 8; 380254721Semaste case 4: // 0B0100 381254721Semaste value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 382254721Semaste if (error.Fail()) 383254721Semaste return false; 384254721Semaste stream.Printf("(long)%" PRId64,value); 385254721Semaste break; 386254721Semaste case 5: // 0B0101 387254721Semaste { 388254721Semaste uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 389254721Semaste if (error.Fail()) 390254721Semaste return false; 391254721Semaste float flt_value = *((float*)&flt_as_int); 392254721Semaste stream.Printf("(float)%f",flt_value); 393254721Semaste break; 394254721Semaste } 395254721Semaste case 6: // 0B0110 396254721Semaste { 397254721Semaste uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 398254721Semaste if (error.Fail()) 399254721Semaste return false; 400254721Semaste double dbl_value = *((double*)&dbl_as_lng); 401254721Semaste stream.Printf("(double)%g",dbl_value); 402254721Semaste break; 403254721Semaste } 404254721Semaste default: 405254721Semaste stream.Printf("unexpected value: dt=%d",data_type); 406254721Semaste break; 407254721Semaste } 408254721Semaste return true; 409254721Semaste } 410254721Semaste } 411254721Semaste else 412254721Semaste { 413254721Semaste return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream); 414254721Semaste } 415254721Semaste} 416254721Semaste 417254721Semastebool 418254721Semastelldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream) 419254721Semaste{ 420254721Semaste ProcessSP process_sp = valobj.GetProcessSP(); 421254721Semaste if (!process_sp) 422254721Semaste return false; 423254721Semaste 424254721Semaste ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 425254721Semaste 426254721Semaste if (!runtime) 427254721Semaste return false; 428254721Semaste 429254721Semaste ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 430254721Semaste 431254721Semaste if (!descriptor.get() || !descriptor->IsValid()) 432254721Semaste return false; 433254721Semaste 434254721Semaste uint32_t ptr_size = process_sp->GetAddressByteSize(); 435254721Semaste 436254721Semaste lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 437254721Semaste 438254721Semaste if (!valobj_addr) 439254721Semaste return false; 440254721Semaste 441254721Semaste const char* class_name = descriptor->GetClassName().GetCString(); 442254721Semaste 443254721Semaste if (!class_name || !*class_name) 444254721Semaste return false; 445254721Semaste 446254721Semaste if (strcmp(class_name, "NSURL") == 0) 447254721Semaste { 448254721Semaste uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit) 449254721Semaste uint64_t offset_base = offset_text + ptr_size; 450254721Semaste ClangASTType type(valobj.GetClangType()); 451254721Semaste ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true)); 452254721Semaste ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true)); 453254721Semaste if (!text) 454254721Semaste return false; 455254721Semaste if (text->GetValueAsUnsigned(0) == 0) 456254721Semaste return false; 457254721Semaste StreamString summary; 458254721Semaste if (!NSStringSummaryProvider(*text, summary)) 459254721Semaste return false; 460254721Semaste if (base && base->GetValueAsUnsigned(0)) 461254721Semaste { 462254721Semaste if (summary.GetSize() > 0) 463254721Semaste summary.GetString().resize(summary.GetSize()-1); 464254721Semaste summary.Printf(" -- "); 465254721Semaste StreamString base_summary; 466254721Semaste if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0) 467254721Semaste summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData()); 468254721Semaste } 469254721Semaste if (summary.GetSize()) 470254721Semaste { 471254721Semaste stream.Printf("%s",summary.GetData()); 472254721Semaste return true; 473254721Semaste } 474254721Semaste } 475254721Semaste else 476254721Semaste { 477254721Semaste return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream); 478254721Semaste } 479254721Semaste return false; 480254721Semaste} 481254721Semaste 482254721Semastebool 483254721Semastelldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream) 484254721Semaste{ 485254721Semaste ProcessSP process_sp = valobj.GetProcessSP(); 486254721Semaste if (!process_sp) 487254721Semaste return false; 488254721Semaste 489254721Semaste ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 490254721Semaste 491254721Semaste if (!runtime) 492254721Semaste return false; 493254721Semaste 494254721Semaste ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 495254721Semaste 496254721Semaste if (!descriptor.get() || !descriptor->IsValid()) 497254721Semaste return false; 498254721Semaste 499254721Semaste uint32_t ptr_size = process_sp->GetAddressByteSize(); 500254721Semaste 501254721Semaste lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 502254721Semaste 503254721Semaste if (!valobj_addr) 504254721Semaste return false; 505254721Semaste 506254721Semaste uint64_t date_value_bits = 0; 507254721Semaste double date_value = 0.0; 508254721Semaste 509254721Semaste const char* class_name = descriptor->GetClassName().GetCString(); 510254721Semaste 511254721Semaste if (!class_name || !*class_name) 512254721Semaste return false; 513254721Semaste 514254721Semaste if (strcmp(class_name,"NSDate") == 0 || 515254721Semaste strcmp(class_name,"__NSDate") == 0 || 516254721Semaste strcmp(class_name,"__NSTaggedDate") == 0) 517254721Semaste { 518254721Semaste uint64_t info_bits=0,value_bits = 0; 519254721Semaste if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits)) 520254721Semaste { 521254721Semaste date_value_bits = ((value_bits << 8) | (info_bits << 4)); 522254721Semaste date_value = *((double*)&date_value_bits); 523254721Semaste } 524254721Semaste else 525254721Semaste { 526254721Semaste Error error; 527254721Semaste date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error); 528254721Semaste date_value = *((double*)&date_value_bits); 529254721Semaste if (error.Fail()) 530254721Semaste return false; 531254721Semaste } 532254721Semaste } 533254721Semaste else if (!strcmp(class_name,"NSCalendarDate")) 534254721Semaste { 535254721Semaste Error error; 536254721Semaste date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error); 537254721Semaste date_value = *((double*)&date_value_bits); 538254721Semaste if (error.Fail()) 539254721Semaste return false; 540254721Semaste } 541254721Semaste else 542254721Semaste { 543254721Semaste if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false) 544254721Semaste return false; 545254721Semaste date_value = *((double*)&date_value_bits); 546254721Semaste } 547254721Semaste if (date_value == -63114076800) 548254721Semaste { 549254721Semaste stream.Printf("0001-12-30 00:00:00 +0000"); 550254721Semaste return true; 551254721Semaste } 552254721Semaste // this snippet of code assumes that time_t == seconds since Jan-1-1970 553254721Semaste // this is generally true and POSIXly happy, but might break if a library 554254721Semaste // vendor decides to get creative 555254721Semaste time_t epoch = GetOSXEpoch(); 556254721Semaste epoch = epoch + (time_t)date_value; 557254721Semaste tm *tm_date = localtime(&epoch); 558254721Semaste if (!tm_date) 559254721Semaste return false; 560254721Semaste std::string buffer(1024,0); 561254721Semaste if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0) 562254721Semaste return false; 563254721Semaste 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()); 564254721Semaste return true; 565254721Semaste} 566