]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/DataFormatters/Cocoa.cpp
Update LLDB snapshot to upstream r225923 (git 2b588ecd)
[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/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, const TypeSummaryOptions& options)
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, options);
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, const TypeSummaryOptions& options)
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, options);
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, const TypeSummaryOptions& options)
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, options);
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, const TypeSummaryOptions& options)
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, const TypeSummaryOptions& options)
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, const TypeSummaryOptions& options)
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                     return false;
346             }
347             return true;
348         }
349         else
350         {
351             Error error;
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;
354             uint64_t value = 0;
355             if (error.Fail())
356                 return false;
357             switch (data_type)
358             {
359                 case 1: // 0B00001
360                     value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
361                     if (error.Fail())
362                         return false;
363                     stream.Printf("(char)%hhd",(char)value);
364                     break;
365                 case 2: // 0B0010
366                     value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
367                     if (error.Fail())
368                         return false;
369                     stream.Printf("(short)%hd",(short)value);
370                     break;
371                 case 3: // 0B0011
372                     value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
373                     if (error.Fail())
374                         return false;
375                     stream.Printf("(int)%d",(int)value);
376                     break;
377                 case 17: // 0B10001
378                     data_location += 8;
379                 case 4: // 0B0100
380                     value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
381                     if (error.Fail())
382                         return false;
383                     stream.Printf("(long)%" PRId64,value);
384                     break;
385                 case 5: // 0B0101
386                 {
387                     uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
388                     if (error.Fail())
389                         return false;
390                     float flt_value = *((float*)&flt_as_int);
391                     stream.Printf("(float)%f",flt_value);
392                     break;
393                 }
394                 case 6: // 0B0110
395                 {
396                     uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
397                     if (error.Fail())
398                         return false;
399                     double dbl_value = *((double*)&dbl_as_lng);
400                     stream.Printf("(double)%g",dbl_value);
401                     break;
402                 }
403                 default:
404                     return false;
405             }
406             return true;
407         }
408     }
409     else
410     {
411         return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
412     }
413 }
414
415 bool
416 lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
417 {
418     ProcessSP process_sp = valobj.GetProcessSP();
419     if (!process_sp)
420         return false;
421     
422     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
423     
424     if (!runtime)
425         return false;
426     
427     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
428     
429     if (!descriptor.get() || !descriptor->IsValid())
430         return false;
431     
432     uint32_t ptr_size = process_sp->GetAddressByteSize();
433     
434     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
435     
436     if (!valobj_addr)
437         return false;
438     
439     const char* class_name = descriptor->GetClassName().GetCString();
440     
441     if (!class_name || !*class_name)
442         return false;
443     
444     if (strcmp(class_name, "NSURL") == 0)
445     {
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));
451         if (!text)
452             return false;
453         if (text->GetValueAsUnsigned(0) == 0)
454             return false;
455         StreamString summary;
456         if (!NSStringSummaryProvider(*text, summary, options))
457             return false;
458         if (base && base->GetValueAsUnsigned(0))
459         {
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, options) && base_summary.GetSize() > 0)
465                 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
466         }
467         if (summary.GetSize())
468         {
469             stream.Printf("%s",summary.GetData());
470             return true;
471         }
472     }
473     else
474     {
475         return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream);
476     }
477     return false;
478 }
479
480 bool
481 lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
482 {
483     ProcessSP process_sp = valobj.GetProcessSP();
484     if (!process_sp)
485         return false;
486     
487     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
488     
489     if (!runtime)
490         return false;
491     
492     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
493     
494     if (!descriptor.get() || !descriptor->IsValid())
495         return false;
496     
497     uint32_t ptr_size = process_sp->GetAddressByteSize();
498     
499     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
500     
501     if (!valobj_addr)
502         return false;
503     
504     uint64_t date_value_bits = 0;
505     double date_value = 0.0;
506     
507     const char* class_name = descriptor->GetClassName().GetCString();
508     
509     if (!class_name || !*class_name)
510         return false;
511     
512     if (strcmp(class_name,"NSDate") == 0 ||
513         strcmp(class_name,"__NSDate") == 0 ||
514         strcmp(class_name,"__NSTaggedDate") == 0)
515     {
516         uint64_t info_bits=0,value_bits = 0;
517         if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
518         {
519             date_value_bits = ((value_bits << 8) | (info_bits << 4));
520             date_value = *((double*)&date_value_bits);
521         }
522         else
523         {
524             Error error;
525             date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
526             date_value = *((double*)&date_value_bits);
527             if (error.Fail())
528                 return false;
529         }
530     }
531     else if (!strcmp(class_name,"NSCalendarDate"))
532     {
533         Error error;
534         date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
535         date_value = *((double*)&date_value_bits);
536         if (error.Fail())
537             return false;
538     }
539     else
540     {
541         if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
542             return false;
543         date_value = *((double*)&date_value_bits);
544     }
545     if (date_value == -63114076800)
546     {
547         stream.Printf("0001-12-30 00:00:00 +0000");
548         return true;
549     }
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 = gmtime(&epoch);
556     if (!tm_date)
557         return false;
558     std::string buffer(1024,0);
559     if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
560         return false;
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());
562     return true;
563 }