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