blob: 28f3d4f1d41b2da82baea63f4ec7906e46a94b3c [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
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
22using namespace lldb;
23using namespace lldb_private;
24using namespace lldb_private::formatters;
25
26bool
Enrico Granataf35bc632014-11-06 21:55:30 +000027lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000028{
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;
Greg Clayton57ee3062013-07-11 22:46:58 +000058 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
Jim Ingham5c42d8a2013-05-15 18:27:08 +000059
Enrico Granata92373532013-03-19 22:58:48 +000060 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +000061 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +000062 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
73bool
Enrico Granataf35bc632014-11-06 21:55:30 +000074lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000075{
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;
Greg Clayton57ee3062013-07-11 22:46:58 +0000105 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000106 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +0000107 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +0000108 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
117bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000118lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000119{
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;
Greg Clayton57ee3062013-07-11 22:46:58 +0000149 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000150 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +0000151 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +0000152 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
163bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000164lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000165{
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
212bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000213lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000214{
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);
Matt Kopecef143712013-06-03 18:00:07 +0000284 stream.Printf("%" PRIu64 " index%s",
Enrico Granata92373532013-03-19 22:58:48 +0000285 count,
286 (count == 1 ? "" : "es"));
287 return true;
288}
289
290bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000291lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000292{
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 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000321 uint64_t value = 0;
322 uint64_t i_bits = 0;
323 if (descriptor->GetTaggedPointerInfo(&i_bits,&value))
Enrico Granata92373532013-03-19 22:58:48 +0000324 {
Enrico Granata92373532013-03-19 22:58:48 +0000325 switch (i_bits)
326 {
327 case 0:
328 stream.Printf("(char)%hhd",(char)value);
329 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000330 case 1:
Enrico Granata92373532013-03-19 22:58:48 +0000331 case 4:
332 stream.Printf("(short)%hd",(short)value);
333 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000334 case 2:
Enrico Granata92373532013-03-19 22:58:48 +0000335 case 8:
336 stream.Printf("(int)%d",(int)value);
337 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000338 case 3:
Enrico Granata92373532013-03-19 22:58:48 +0000339 case 12:
340 stream.Printf("(long)%" PRId64,value);
341 break;
342 default:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000343 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000344 }
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:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000402 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000403 }
404 return true;
405 }
406 }
407 else
408 {
409 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
410 }
411}
412
413bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000414lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000415{
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;
Greg Clayton57ee3062013-07-11 22:46:58 +0000446 ClangASTType type(valobj.GetClangType());
Enrico Granata92373532013-03-19 22:58:48 +0000447 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;
Enrico Granataf35bc632014-11-06 21:55:30 +0000454 if (!NSStringSummaryProvider(*text, summary, options))
Enrico Granata92373532013-03-19 22:58:48 +0000455 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;
Enrico Granataf35bc632014-11-06 21:55:30 +0000462 if (NSURLSummaryProvider(*base, base_summary, options) && base_summary.GetSize() > 0)
Enrico Granata92373532013-03-19 22:58:48 +0000463 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
478bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000479lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000480{
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 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000514 uint64_t info_bits=0,value_bits = 0;
515 if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
Enrico Granata92373532013-03-19 22:58:48 +0000516 {
Enrico Granata92373532013-03-19 22:58:48 +0000517 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;
Enrico Granatadb2ecad2014-10-15 20:18:58 +0000553 tm *tm_date = gmtime(&epoch);
Enrico Granata92373532013-03-19 22:58:48 +0000554 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}