]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/tools/lldb/source/DataFormatters/Cocoa.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / tools / lldb / source / DataFormatters / Cocoa.cpp
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 "lldb/lldb-python.h"
11
12 #include "lldb/DataFormatters/CXXFormatterFunctions.h"
13
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"
23
24 using namespace lldb;
25 using namespace lldb_private;
26 using namespace lldb_private::formatters;
27
28 bool
29 lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream)
30 {
31     ProcessSP process_sp = valobj.GetProcessSP();
32     if (!process_sp)
33         return false;
34     
35     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
36     
37     if (!runtime)
38         return false;
39     
40     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
41     
42     if (!descriptor.get() || !descriptor->IsValid())
43         return false;
44     
45     uint32_t ptr_size = process_sp->GetAddressByteSize();
46     
47     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
48     
49     if (!valobj_addr)
50         return false;
51     
52     const char* class_name = descriptor->GetClassName().GetCString();
53     
54     if (!class_name || !*class_name)
55         return false;
56     
57     if (!strcmp(class_name,"NSBundle"))
58     {
59         uint64_t offset = 5 * ptr_size;
60         ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
61
62         StreamString summary_stream;
63         bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
64         if (was_nsstring_ok && summary_stream.GetSize() > 0)
65         {
66             stream.Printf("%s",summary_stream.GetData());
67             return true;
68         }
69     }
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);
73 }
74
75 bool
76 lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream)
77 {
78     ProcessSP process_sp = valobj.GetProcessSP();
79     if (!process_sp)
80         return false;
81     
82     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
83     
84     if (!runtime)
85         return false;
86     
87     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
88     
89     if (!descriptor.get() || !descriptor->IsValid())
90         return false;
91     
92     uint32_t ptr_size = process_sp->GetAddressByteSize();
93     
94     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
95     
96     if (!valobj_addr)
97         return false;
98     
99     const char* class_name = descriptor->GetClassName().GetCString();
100     
101     if (!class_name || !*class_name)
102         return false;
103     
104     if (!strcmp(class_name,"__NSTimeZone"))
105     {
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)
111         {
112             stream.Printf("%s",summary_stream.GetData());
113             return true;
114         }
115     }
116     return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
117 }
118
119 bool
120 lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream)
121 {
122     ProcessSP process_sp = valobj.GetProcessSP();
123     if (!process_sp)
124         return false;
125     
126     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
127     
128     if (!runtime)
129         return false;
130     
131     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
132     
133     if (!descriptor.get() || !descriptor->IsValid())
134         return false;
135     
136     uint32_t ptr_size = process_sp->GetAddressByteSize();
137     
138     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
139     
140     if (!valobj_addr)
141         return false;
142     
143     const char* class_name = descriptor->GetClassName().GetCString();
144     
145     if (!class_name || !*class_name)
146         return false;
147     
148     if (!strcmp(class_name,"NSConcreteNotification"))
149     {
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)
155         {
156             stream.Printf("%s",summary_stream.GetData());
157             return true;
158         }
159     }
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);
163 }
164
165 bool
166 lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream)
167 {
168     ProcessSP process_sp = valobj.GetProcessSP();
169     if (!process_sp)
170         return false;
171     
172     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
173     
174     if (!runtime)
175         return false;
176     
177     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
178     
179     if (!descriptor.get() || !descriptor->IsValid())
180         return false;
181     
182     uint32_t ptr_size = process_sp->GetAddressByteSize();
183     
184     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
185     
186     if (!valobj_addr)
187         return false;
188     
189     const char* class_name = descriptor->GetClassName().GetCString();
190     
191     if (!class_name || !*class_name)
192         return false;
193     
194     uint64_t port_number = 0;
195     
196     do
197     {
198         if (!strcmp(class_name,"NSMachPort"))
199         {
200             uint64_t offset = (ptr_size == 4 ? 12 : 20);
201             Error error;
202             port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error);
203             if (error.Success())
204                 break;
205         }
206         if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number))
207             return false;
208     } while (false);
209     
210     stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF));
211     return true;
212 }
213
214 bool
215 lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream)
216 {
217     ProcessSP process_sp = valobj.GetProcessSP();
218     if (!process_sp)
219         return false;
220     
221     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
222     
223     if (!runtime)
224         return false;
225     
226     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
227     
228     if (!descriptor.get() || !descriptor->IsValid())
229         return false;
230     
231     uint32_t ptr_size = process_sp->GetAddressByteSize();
232     
233     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
234     
235     if (!valobj_addr)
236         return false;
237     
238     const char* class_name = descriptor->GetClassName().GetCString();
239     
240     if (!class_name || !*class_name)
241         return false;
242     
243     uint64_t count = 0;
244     
245     do {
246         if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet"))
247         {
248             Error error;
249             uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error);
250             if (error.Fail())
251                 return false;
252             // this means the set is empty - count = 0
253             if ((mode & 1) == 1)
254             {
255                 count = 0;
256                 break;
257             }
258             if ((mode & 2) == 2)
259                 mode = 1; // this means the set only has one range
260             else
261                 mode = 2; // this means the set has multiple ranges
262             if (mode == 1)
263             {
264                 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error);
265                 if (error.Fail())
266                     return false;
267             }
268             else
269             {
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);
272                 if (error.Fail())
273                     return false;
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);
276                 if (error.Fail())
277                     return false;
278             }
279         }
280         else
281         {
282             if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count))
283                 return false;
284         }
285     }  while (false);
286     stream.Printf("%" PRIu64 " index%s",
287                   count,
288                   (count == 1 ? "" : "es"));
289     return true;
290 }
291
292 bool
293 lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream)
294 {
295     ProcessSP process_sp = valobj.GetProcessSP();
296     if (!process_sp)
297         return false;
298     
299     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
300     
301     if (!runtime)
302         return false;
303     
304     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
305     
306     if (!descriptor.get() || !descriptor->IsValid())
307         return false;
308     
309     uint32_t ptr_size = process_sp->GetAddressByteSize();
310     
311     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
312     
313     if (!valobj_addr)
314         return false;
315     
316     const char* class_name = descriptor->GetClassName().GetCString();
317     
318     if (!class_name || !*class_name)
319         return false;
320     
321     if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
322     {
323         uint64_t value = 0;
324         uint64_t i_bits = 0;
325         if (descriptor->GetTaggedPointerInfo(&i_bits,&value))
326         {
327             switch (i_bits)
328             {
329                 case 0:
330                     stream.Printf("(char)%hhd",(char)value);
331                     break;
332                 case 1:
333                 case 4:
334                     stream.Printf("(short)%hd",(short)value);
335                     break;
336                 case 2:
337                 case 8:
338                     stream.Printf("(int)%d",(int)value);
339                     break;
340                 case 3:
341                 case 12:
342                     stream.Printf("(long)%" PRId64,value);
343                     break;
344                 default:
345                     stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value);
346                     break;
347             }
348             return true;
349         }
350         else
351         {
352             Error error;
353             uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
354             uint64_t data_location = valobj_addr + 2*ptr_size;
355             uint64_t value = 0;
356             if (error.Fail())
357                 return false;
358             switch (data_type)
359             {
360                 case 1: // 0B00001
361                     value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
362                     if (error.Fail())
363                         return false;
364                     stream.Printf("(char)%hhd",(char)value);
365                     break;
366                 case 2: // 0B0010
367                     value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
368                     if (error.Fail())
369                         return false;
370                     stream.Printf("(short)%hd",(short)value);
371                     break;
372                 case 3: // 0B0011
373                     value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
374                     if (error.Fail())
375                         return false;
376                     stream.Printf("(int)%d",(int)value);
377                     break;
378                 case 17: // 0B10001
379                     data_location += 8;
380                 case 4: // 0B0100
381                     value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
382                     if (error.Fail())
383                         return false;
384                     stream.Printf("(long)%" PRId64,value);
385                     break;
386                 case 5: // 0B0101
387                 {
388                     uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
389                     if (error.Fail())
390                         return false;
391                     float flt_value = *((float*)&flt_as_int);
392                     stream.Printf("(float)%f",flt_value);
393                     break;
394                 }
395                 case 6: // 0B0110
396                 {
397                     uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
398                     if (error.Fail())
399                         return false;
400                     double dbl_value = *((double*)&dbl_as_lng);
401                     stream.Printf("(double)%g",dbl_value);
402                     break;
403                 }
404                 default:
405                     stream.Printf("unexpected value: dt=%d",data_type);
406                     break;
407             }
408             return true;
409         }
410     }
411     else
412     {
413         return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
414     }
415 }
416
417 bool
418 lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream)
419 {
420     ProcessSP process_sp = valobj.GetProcessSP();
421     if (!process_sp)
422         return false;
423     
424     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
425     
426     if (!runtime)
427         return false;
428     
429     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
430     
431     if (!descriptor.get() || !descriptor->IsValid())
432         return false;
433     
434     uint32_t ptr_size = process_sp->GetAddressByteSize();
435     
436     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
437     
438     if (!valobj_addr)
439         return false;
440     
441     const char* class_name = descriptor->GetClassName().GetCString();
442     
443     if (!class_name || !*class_name)
444         return false;
445     
446     if (strcmp(class_name, "NSURL") == 0)
447     {
448         uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit)
449         uint64_t offset_base = offset_text + ptr_size;
450         ClangASTType type(valobj.GetClangType());
451         ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
452         ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
453         if (!text)
454             return false;
455         if (text->GetValueAsUnsigned(0) == 0)
456             return false;
457         StreamString summary;
458         if (!NSStringSummaryProvider(*text, summary))
459             return false;
460         if (base && base->GetValueAsUnsigned(0))
461         {
462             if (summary.GetSize() > 0)
463                 summary.GetString().resize(summary.GetSize()-1);
464             summary.Printf(" -- ");
465             StreamString base_summary;
466             if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0)
467                 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
468         }
469         if (summary.GetSize())
470         {
471             stream.Printf("%s",summary.GetData());
472             return true;
473         }
474     }
475     else
476     {
477         return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream);
478     }
479     return false;
480 }
481
482 bool
483 lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream)
484 {
485     ProcessSP process_sp = valobj.GetProcessSP();
486     if (!process_sp)
487         return false;
488     
489     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
490     
491     if (!runtime)
492         return false;
493     
494     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
495     
496     if (!descriptor.get() || !descriptor->IsValid())
497         return false;
498     
499     uint32_t ptr_size = process_sp->GetAddressByteSize();
500     
501     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
502     
503     if (!valobj_addr)
504         return false;
505     
506     uint64_t date_value_bits = 0;
507     double date_value = 0.0;
508     
509     const char* class_name = descriptor->GetClassName().GetCString();
510     
511     if (!class_name || !*class_name)
512         return false;
513     
514     if (strcmp(class_name,"NSDate") == 0 ||
515         strcmp(class_name,"__NSDate") == 0 ||
516         strcmp(class_name,"__NSTaggedDate") == 0)
517     {
518         uint64_t info_bits=0,value_bits = 0;
519         if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
520         {
521             date_value_bits = ((value_bits << 8) | (info_bits << 4));
522             date_value = *((double*)&date_value_bits);
523         }
524         else
525         {
526             Error error;
527             date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
528             date_value = *((double*)&date_value_bits);
529             if (error.Fail())
530                 return false;
531         }
532     }
533     else if (!strcmp(class_name,"NSCalendarDate"))
534     {
535         Error error;
536         date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
537         date_value = *((double*)&date_value_bits);
538         if (error.Fail())
539             return false;
540     }
541     else
542     {
543         if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
544             return false;
545         date_value = *((double*)&date_value_bits);
546     }
547     if (date_value == -63114076800)
548     {
549         stream.Printf("0001-12-30 00:00:00 +0000");
550         return true;
551     }
552     // this snippet of code assumes that time_t == seconds since Jan-1-1970
553     // this is generally true and POSIXly happy, but might break if a library
554     // vendor decides to get creative
555     time_t epoch = GetOSXEpoch();
556     epoch = epoch + (time_t)date_value;
557     tm *tm_date = localtime(&epoch);
558     if (!tm_date)
559         return false;
560     std::string buffer(1024,0);
561     if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
562         return false;
563     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());
564     return true;
565 }