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