1 //===-- Cocoa.cpp -------------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/lldb-python.h"
12 #include "lldb/DataFormatters/CXXFormatterFunctions.h"
14 #include "lldb/Core/DataBufferHeap.h"
15 #include "lldb/Core/Error.h"
16 #include "lldb/Core/Stream.h"
17 #include "lldb/Core/ValueObject.h"
18 #include "lldb/Core/ValueObjectConstResult.h"
19 #include "lldb/Host/Endian.h"
20 #include "lldb/Symbol/ClangASTContext.h"
21 #include "lldb/Target/ObjCLanguageRuntime.h"
22 #include "lldb/Target/Target.h"
25 using namespace lldb_private;
26 using namespace lldb_private::formatters;
29 lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream)
31 ProcessSP process_sp = valobj.GetProcessSP();
35 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
40 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
42 if (!descriptor.get() || !descriptor->IsValid())
45 uint32_t ptr_size = process_sp->GetAddressByteSize();
47 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
52 const char* class_name = descriptor->GetClassName().GetCString();
54 if (!class_name || !*class_name)
57 if (!strcmp(class_name,"NSBundle"))
59 uint64_t offset = 5 * ptr_size;
60 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
62 StreamString summary_stream;
63 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
64 if (was_nsstring_ok && summary_stream.GetSize() > 0)
66 stream.Printf("%s",summary_stream.GetData());
70 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
71 // which is encoded differently and needs to be handled by running code
72 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream);
76 lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream)
78 ProcessSP process_sp = valobj.GetProcessSP();
82 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
87 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
89 if (!descriptor.get() || !descriptor->IsValid())
92 uint32_t ptr_size = process_sp->GetAddressByteSize();
94 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
99 const char* class_name = descriptor->GetClassName().GetCString();
101 if (!class_name || !*class_name)
104 if (!strcmp(class_name,"__NSTimeZone"))
106 uint64_t offset = ptr_size;
107 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
108 StreamString summary_stream;
109 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
110 if (was_nsstring_ok && summary_stream.GetSize() > 0)
112 stream.Printf("%s",summary_stream.GetData());
116 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
120 lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream)
122 ProcessSP process_sp = valobj.GetProcessSP();
126 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
131 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
133 if (!descriptor.get() || !descriptor->IsValid())
136 uint32_t ptr_size = process_sp->GetAddressByteSize();
138 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
143 const char* class_name = descriptor->GetClassName().GetCString();
145 if (!class_name || !*class_name)
148 if (!strcmp(class_name,"NSConcreteNotification"))
150 uint64_t offset = ptr_size;
151 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
152 StreamString summary_stream;
153 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
154 if (was_nsstring_ok && summary_stream.GetSize() > 0)
156 stream.Printf("%s",summary_stream.GetData());
160 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
161 // which is encoded differently and needs to be handled by running code
162 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
166 lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream)
168 ProcessSP process_sp = valobj.GetProcessSP();
172 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
177 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
179 if (!descriptor.get() || !descriptor->IsValid())
182 uint32_t ptr_size = process_sp->GetAddressByteSize();
184 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
189 const char* class_name = descriptor->GetClassName().GetCString();
191 if (!class_name || !*class_name)
194 uint64_t port_number = 0;
198 if (!strcmp(class_name,"NSMachPort"))
200 uint64_t offset = (ptr_size == 4 ? 12 : 20);
202 port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error);
206 if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number))
210 stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF));
215 lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream)
217 ProcessSP process_sp = valobj.GetProcessSP();
221 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
226 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
228 if (!descriptor.get() || !descriptor->IsValid())
231 uint32_t ptr_size = process_sp->GetAddressByteSize();
233 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
238 const char* class_name = descriptor->GetClassName().GetCString();
240 if (!class_name || !*class_name)
246 if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet"))
249 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error);
252 // this means the set is empty - count = 0
259 mode = 1; // this means the set only has one range
261 mode = 2; // this means the set has multiple ranges
264 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error);
270 // read a pointer to the data at 2*ptr_size
271 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
274 // read the data at 2*ptr_size from the first location
275 count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error);
282 if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count))
286 stream.Printf("%" PRIu64 " index%s",
288 (count == 1 ? "" : "es"));
293 lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream)
295 ProcessSP process_sp = valobj.GetProcessSP();
299 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
304 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
306 if (!descriptor.get() || !descriptor->IsValid())
309 uint32_t ptr_size = process_sp->GetAddressByteSize();
311 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
316 const char* class_name = descriptor->GetClassName().GetCString();
318 if (!class_name || !*class_name)
321 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
325 if (descriptor->GetTaggedPointerInfo(&i_bits,&value))
330 stream.Printf("(char)%hhd",(char)value);
334 stream.Printf("(short)%hd",(short)value);
338 stream.Printf("(int)%d",(int)value);
342 stream.Printf("(long)%" PRId64,value);
352 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
353 uint64_t data_location = valobj_addr + 2*ptr_size;
360 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
363 stream.Printf("(char)%hhd",(char)value);
366 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
369 stream.Printf("(short)%hd",(short)value);
372 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
375 stream.Printf("(int)%d",(int)value);
380 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
383 stream.Printf("(long)%" PRId64,value);
387 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
390 float flt_value = *((float*)&flt_as_int);
391 stream.Printf("(float)%f",flt_value);
396 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
399 double dbl_value = *((double*)&dbl_as_lng);
400 stream.Printf("(double)%g",dbl_value);
411 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
416 lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream)
418 ProcessSP process_sp = valobj.GetProcessSP();
422 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
427 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
429 if (!descriptor.get() || !descriptor->IsValid())
432 uint32_t ptr_size = process_sp->GetAddressByteSize();
434 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
439 const char* class_name = descriptor->GetClassName().GetCString();
441 if (!class_name || !*class_name)
444 if (strcmp(class_name, "NSURL") == 0)
446 uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit)
447 uint64_t offset_base = offset_text + ptr_size;
448 ClangASTType type(valobj.GetClangType());
449 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
450 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
453 if (text->GetValueAsUnsigned(0) == 0)
455 StreamString summary;
456 if (!NSStringSummaryProvider(*text, summary))
458 if (base && base->GetValueAsUnsigned(0))
460 if (summary.GetSize() > 0)
461 summary.GetString().resize(summary.GetSize()-1);
462 summary.Printf(" -- ");
463 StreamString base_summary;
464 if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0)
465 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
467 if (summary.GetSize())
469 stream.Printf("%s",summary.GetData());
475 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream);
481 lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream)
483 ProcessSP process_sp = valobj.GetProcessSP();
487 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
492 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
494 if (!descriptor.get() || !descriptor->IsValid())
497 uint32_t ptr_size = process_sp->GetAddressByteSize();
499 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
504 uint64_t date_value_bits = 0;
505 double date_value = 0.0;
507 const char* class_name = descriptor->GetClassName().GetCString();
509 if (!class_name || !*class_name)
512 if (strcmp(class_name,"NSDate") == 0 ||
513 strcmp(class_name,"__NSDate") == 0 ||
514 strcmp(class_name,"__NSTaggedDate") == 0)
516 uint64_t info_bits=0,value_bits = 0;
517 if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
519 date_value_bits = ((value_bits << 8) | (info_bits << 4));
520 date_value = *((double*)&date_value_bits);
525 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
526 date_value = *((double*)&date_value_bits);
531 else if (!strcmp(class_name,"NSCalendarDate"))
534 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
535 date_value = *((double*)&date_value_bits);
541 if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
543 date_value = *((double*)&date_value_bits);
545 if (date_value == -63114076800)
547 stream.Printf("0001-12-30 00:00:00 +0000");
550 // this snippet of code assumes that time_t == seconds since Jan-1-1970
551 // this is generally true and POSIXly happy, but might break if a library
552 // vendor decides to get creative
553 time_t epoch = GetOSXEpoch();
554 epoch = epoch + (time_t)date_value;
555 tm *tm_date = localtime(&epoch);
558 std::string buffer(1024,0);
559 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
561 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());