blob: bb8dc53c466c34a121cd5ae0039005eb80b80ee1 [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;
Greg Clayton57ee3062013-07-11 22:46:58 +000060 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
Jim Ingham5c42d8a2013-05-15 18:27:08 +000061
Enrico Granata92373532013-03-19 22:58:48 +000062 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
75bool
76lldb_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;
Greg Clayton57ee3062013-07-11 22:46:58 +0000107 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000108 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
119bool
120lldb_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;
Greg Clayton57ee3062013-07-11 22:46:58 +0000151 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000152 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
165bool
166lldb_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
214bool
215lldb_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);
Matt Kopecef143712013-06-03 18:00:07 +0000286 stream.Printf("%" PRIu64 " index%s",
Enrico Granata92373532013-03-19 22:58:48 +0000287 count,
288 (count == 1 ? "" : "es"));
289 return true;
290}
291
292bool
293lldb_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 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000323 uint64_t value = 0;
324 uint64_t i_bits = 0;
325 if (descriptor->GetTaggedPointerInfo(&i_bits,&value))
Enrico Granata92373532013-03-19 22:58:48 +0000326 {
Enrico Granata92373532013-03-19 22:58:48 +0000327 switch (i_bits)
328 {
329 case 0:
330 stream.Printf("(char)%hhd",(char)value);
331 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000332 case 1:
Enrico Granata92373532013-03-19 22:58:48 +0000333 case 4:
334 stream.Printf("(short)%hd",(short)value);
335 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000336 case 2:
Enrico Granata92373532013-03-19 22:58:48 +0000337 case 8:
338 stream.Printf("(int)%d",(int)value);
339 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000340 case 3:
Enrico Granata92373532013-03-19 22:58:48 +0000341 case 12:
342 stream.Printf("(long)%" PRId64,value);
343 break;
344 default:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000345 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000346 }
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:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000404 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000405 }
406 return true;
407 }
408 }
409 else
410 {
411 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
412 }
413}
414
415bool
416lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream)
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;
Greg Clayton57ee3062013-07-11 22:46:58 +0000448 ClangASTType type(valobj.GetClangType());
Enrico Granata92373532013-03-19 22:58:48 +0000449 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))
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) && 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
480bool
481lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream)
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 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000516 uint64_t info_bits=0,value_bits = 0;
517 if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
Enrico Granata92373532013-03-19 22:58:48 +0000518 {
Enrico Granata92373532013-03-19 22:58:48 +0000519 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;
Enrico Granatadb2ecad2014-10-15 20:18:58 +0000555 tm *tm_date = gmtime(&epoch);
Enrico Granata92373532013-03-19 22:58:48 +0000556 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}