blob: 84699a20b6020488375fe06e5d324965f54eb838 [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
Enrico Granata170c3952015-09-14 22:18:32 +000010#include "Cocoa.h"
Enrico Granata92373532013-03-19 22:58:48 +000011
12#include "lldb/Core/DataBufferHeap.h"
13#include "lldb/Core/Error.h"
Enrico Granata7de855c2015-10-02 20:59:58 +000014#include "lldb/Core/Mangled.h"
Enrico Granata92373532013-03-19 22:58:48 +000015#include "lldb/Core/Stream.h"
16#include "lldb/Core/ValueObject.h"
17#include "lldb/Core/ValueObjectConstResult.h"
Enrico Granata419d7912015-09-04 00:33:51 +000018#include "lldb/DataFormatters/FormattersHelpers.h"
19#include "lldb/DataFormatters/StringPrinter.h"
20#include "lldb/DataFormatters/TypeSummary.h"
Enrico Granata92373532013-03-19 22:58:48 +000021#include "lldb/Host/Endian.h"
22#include "lldb/Symbol/ClangASTContext.h"
23#include "lldb/Target/ObjCLanguageRuntime.h"
24#include "lldb/Target/Target.h"
Enrico Granata419d7912015-09-04 00:33:51 +000025#include "lldb/Target/Process.h"
Enrico Granatad87cc312015-09-03 01:29:42 +000026#include "lldb/Utility/ProcessStructReader.h"
27
Enrico Granata7de855c2015-10-02 20:59:58 +000028#include "NSString.h"
29
Enrico Granata92373532013-03-19 22:58:48 +000030using namespace lldb;
31using namespace lldb_private;
32using namespace lldb_private::formatters;
33
34bool
Enrico Granataf35bc632014-11-06 21:55:30 +000035lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000036{
37 ProcessSP process_sp = valobj.GetProcessSP();
38 if (!process_sp)
39 return false;
40
41 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
42
43 if (!runtime)
44 return false;
45
46 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
47
48 if (!descriptor.get() || !descriptor->IsValid())
49 return false;
50
51 uint32_t ptr_size = process_sp->GetAddressByteSize();
52
53 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
54
55 if (!valobj_addr)
56 return false;
57
58 const char* class_name = descriptor->GetClassName().GetCString();
59
60 if (!class_name || !*class_name)
61 return false;
62
63 if (!strcmp(class_name,"NSBundle"))
64 {
65 uint64_t offset = 5 * ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +000066 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
Jim Ingham5c42d8a2013-05-15 18:27:08 +000067
Enrico Granata92373532013-03-19 22:58:48 +000068 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +000069 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +000070 if (was_nsstring_ok && summary_stream.GetSize() > 0)
71 {
72 stream.Printf("%s",summary_stream.GetData());
73 return true;
74 }
75 }
76 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
77 // which is encoded differently and needs to be handled by running code
Enrico Granata31fda932015-10-07 01:41:23 +000078 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +000079}
80
81bool
Enrico Granataf35bc632014-11-06 21:55:30 +000082lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000083{
84 ProcessSP process_sp = valobj.GetProcessSP();
85 if (!process_sp)
86 return false;
87
88 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
89
90 if (!runtime)
91 return false;
92
93 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
94
95 if (!descriptor.get() || !descriptor->IsValid())
96 return false;
97
98 uint32_t ptr_size = process_sp->GetAddressByteSize();
99
100 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
101
102 if (!valobj_addr)
103 return false;
104
105 const char* class_name = descriptor->GetClassName().GetCString();
106
107 if (!class_name || !*class_name)
108 return false;
109
110 if (!strcmp(class_name,"__NSTimeZone"))
111 {
112 uint64_t offset = ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +0000113 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000114 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +0000115 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +0000116 if (was_nsstring_ok && summary_stream.GetSize() > 0)
117 {
118 stream.Printf("%s",summary_stream.GetData());
119 return true;
120 }
121 }
Enrico Granata31fda932015-10-07 01:41:23 +0000122 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000123}
124
125bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000126lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000127{
128 ProcessSP process_sp = valobj.GetProcessSP();
129 if (!process_sp)
130 return false;
131
132 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
133
134 if (!runtime)
135 return false;
136
137 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
138
139 if (!descriptor.get() || !descriptor->IsValid())
140 return false;
141
142 uint32_t ptr_size = process_sp->GetAddressByteSize();
143
144 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
145
146 if (!valobj_addr)
147 return false;
148
149 const char* class_name = descriptor->GetClassName().GetCString();
150
151 if (!class_name || !*class_name)
152 return false;
153
154 if (!strcmp(class_name,"NSConcreteNotification"))
155 {
156 uint64_t offset = ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +0000157 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000158 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +0000159 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +0000160 if (was_nsstring_ok && summary_stream.GetSize() > 0)
161 {
162 stream.Printf("%s",summary_stream.GetData());
163 return true;
164 }
165 }
166 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
167 // which is encoded differently and needs to be handled by running code
Enrico Granata31fda932015-10-07 01:41:23 +0000168 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000169}
170
171bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000172lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000173{
174 ProcessSP process_sp = valobj.GetProcessSP();
175 if (!process_sp)
176 return false;
177
178 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
179
180 if (!runtime)
181 return false;
182
183 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
184
185 if (!descriptor.get() || !descriptor->IsValid())
186 return false;
187
188 uint32_t ptr_size = process_sp->GetAddressByteSize();
189
190 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
191
192 if (!valobj_addr)
193 return false;
194
195 const char* class_name = descriptor->GetClassName().GetCString();
196
197 if (!class_name || !*class_name)
198 return false;
199
200 uint64_t port_number = 0;
201
202 do
203 {
204 if (!strcmp(class_name,"NSMachPort"))
205 {
206 uint64_t offset = (ptr_size == 4 ? 12 : 20);
207 Error error;
208 port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error);
209 if (error.Success())
210 break;
211 }
212 if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number))
213 return false;
214 } while (false);
215
216 stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF));
217 return true;
218}
219
220bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000221lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000222{
223 ProcessSP process_sp = valobj.GetProcessSP();
224 if (!process_sp)
225 return false;
226
227 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
228
229 if (!runtime)
230 return false;
231
232 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
233
234 if (!descriptor.get() || !descriptor->IsValid())
235 return false;
236
237 uint32_t ptr_size = process_sp->GetAddressByteSize();
238
239 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
240
241 if (!valobj_addr)
242 return false;
243
244 const char* class_name = descriptor->GetClassName().GetCString();
245
246 if (!class_name || !*class_name)
247 return false;
248
249 uint64_t count = 0;
250
251 do {
252 if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet"))
253 {
254 Error error;
255 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error);
256 if (error.Fail())
257 return false;
258 // this means the set is empty - count = 0
259 if ((mode & 1) == 1)
260 {
261 count = 0;
262 break;
263 }
264 if ((mode & 2) == 2)
265 mode = 1; // this means the set only has one range
266 else
267 mode = 2; // this means the set has multiple ranges
268 if (mode == 1)
269 {
270 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error);
271 if (error.Fail())
272 return false;
273 }
274 else
275 {
276 // read a pointer to the data at 2*ptr_size
277 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
278 if (error.Fail())
279 return false;
280 // read the data at 2*ptr_size from the first location
281 count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error);
282 if (error.Fail())
283 return false;
284 }
285 }
286 else
287 {
288 if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count))
289 return false;
290 }
291 } while (false);
Matt Kopecef143712013-06-03 18:00:07 +0000292 stream.Printf("%" PRIu64 " index%s",
Enrico Granata92373532013-03-19 22:58:48 +0000293 count,
294 (count == 1 ? "" : "es"));
295 return true;
296}
297
298bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000299lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000300{
301 ProcessSP process_sp = valobj.GetProcessSP();
302 if (!process_sp)
303 return false;
304
305 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
306
307 if (!runtime)
308 return false;
309
310 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
311
312 if (!descriptor.get() || !descriptor->IsValid())
313 return false;
314
315 uint32_t ptr_size = process_sp->GetAddressByteSize();
316
317 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
318
319 if (!valobj_addr)
320 return false;
321
322 const char* class_name = descriptor->GetClassName().GetCString();
323
324 if (!class_name || !*class_name)
325 return false;
326
327 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
328 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000329 uint64_t value = 0;
330 uint64_t i_bits = 0;
331 if (descriptor->GetTaggedPointerInfo(&i_bits,&value))
Enrico Granata92373532013-03-19 22:58:48 +0000332 {
Enrico Granata92373532013-03-19 22:58:48 +0000333 switch (i_bits)
334 {
335 case 0:
336 stream.Printf("(char)%hhd",(char)value);
337 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000338 case 1:
Enrico Granata92373532013-03-19 22:58:48 +0000339 case 4:
340 stream.Printf("(short)%hd",(short)value);
341 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000342 case 2:
Enrico Granata92373532013-03-19 22:58:48 +0000343 case 8:
344 stream.Printf("(int)%d",(int)value);
345 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000346 case 3:
Enrico Granata92373532013-03-19 22:58:48 +0000347 case 12:
348 stream.Printf("(long)%" PRId64,value);
349 break;
350 default:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000351 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000352 }
353 return true;
354 }
355 else
356 {
357 Error error;
358 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
359 uint64_t data_location = valobj_addr + 2*ptr_size;
360 uint64_t value = 0;
361 if (error.Fail())
362 return false;
363 switch (data_type)
364 {
365 case 1: // 0B00001
366 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
367 if (error.Fail())
368 return false;
369 stream.Printf("(char)%hhd",(char)value);
370 break;
371 case 2: // 0B0010
372 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
373 if (error.Fail())
374 return false;
375 stream.Printf("(short)%hd",(short)value);
376 break;
377 case 3: // 0B0011
378 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
379 if (error.Fail())
380 return false;
381 stream.Printf("(int)%d",(int)value);
382 break;
383 case 17: // 0B10001
384 data_location += 8;
385 case 4: // 0B0100
386 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
387 if (error.Fail())
388 return false;
389 stream.Printf("(long)%" PRId64,value);
390 break;
391 case 5: // 0B0101
392 {
393 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
394 if (error.Fail())
395 return false;
396 float flt_value = *((float*)&flt_as_int);
397 stream.Printf("(float)%f",flt_value);
398 break;
399 }
400 case 6: // 0B0110
401 {
402 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
403 if (error.Fail())
404 return false;
405 double dbl_value = *((double*)&dbl_as_lng);
406 stream.Printf("(double)%g",dbl_value);
407 break;
408 }
409 default:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000410 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000411 }
412 return true;
413 }
414 }
415 else
416 {
Enrico Granata31fda932015-10-07 01:41:23 +0000417 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000418 }
419}
420
421bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000422lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000423{
424 ProcessSP process_sp = valobj.GetProcessSP();
425 if (!process_sp)
426 return false;
427
428 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
429
430 if (!runtime)
431 return false;
432
433 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
434
435 if (!descriptor.get() || !descriptor->IsValid())
436 return false;
437
438 uint32_t ptr_size = process_sp->GetAddressByteSize();
439
440 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
441
442 if (!valobj_addr)
443 return false;
444
445 const char* class_name = descriptor->GetClassName().GetCString();
446
447 if (!class_name || !*class_name)
448 return false;
449
450 if (strcmp(class_name, "NSURL") == 0)
451 {
452 uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit)
453 uint64_t offset_base = offset_text + ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +0000454 CompilerType type(valobj.GetCompilerType());
Enrico Granata92373532013-03-19 22:58:48 +0000455 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
456 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
457 if (!text)
458 return false;
459 if (text->GetValueAsUnsigned(0) == 0)
460 return false;
461 StreamString summary;
Enrico Granataf35bc632014-11-06 21:55:30 +0000462 if (!NSStringSummaryProvider(*text, summary, options))
Enrico Granata92373532013-03-19 22:58:48 +0000463 return false;
464 if (base && base->GetValueAsUnsigned(0))
465 {
466 if (summary.GetSize() > 0)
467 summary.GetString().resize(summary.GetSize()-1);
468 summary.Printf(" -- ");
469 StreamString base_summary;
Enrico Granataf35bc632014-11-06 21:55:30 +0000470 if (NSURLSummaryProvider(*base, base_summary, options) && base_summary.GetSize() > 0)
Enrico Granata92373532013-03-19 22:58:48 +0000471 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
472 }
473 if (summary.GetSize())
474 {
475 stream.Printf("%s",summary.GetData());
476 return true;
477 }
478 }
479 else
480 {
Enrico Granata31fda932015-10-07 01:41:23 +0000481 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000482 }
483 return false;
484}
485
486bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000487lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000488{
489 ProcessSP process_sp = valobj.GetProcessSP();
490 if (!process_sp)
491 return false;
492
493 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
494
495 if (!runtime)
496 return false;
497
498 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
499
500 if (!descriptor.get() || !descriptor->IsValid())
501 return false;
502
503 uint32_t ptr_size = process_sp->GetAddressByteSize();
504
505 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
506
507 if (!valobj_addr)
508 return false;
509
510 uint64_t date_value_bits = 0;
511 double date_value = 0.0;
512
513 const char* class_name = descriptor->GetClassName().GetCString();
514
515 if (!class_name || !*class_name)
516 return false;
517
518 if (strcmp(class_name,"NSDate") == 0 ||
519 strcmp(class_name,"__NSDate") == 0 ||
520 strcmp(class_name,"__NSTaggedDate") == 0)
521 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000522 uint64_t info_bits=0,value_bits = 0;
523 if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
Enrico Granata92373532013-03-19 22:58:48 +0000524 {
Enrico Granata92373532013-03-19 22:58:48 +0000525 date_value_bits = ((value_bits << 8) | (info_bits << 4));
526 date_value = *((double*)&date_value_bits);
527 }
528 else
529 {
530 Error error;
531 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
532 date_value = *((double*)&date_value_bits);
533 if (error.Fail())
534 return false;
535 }
536 }
537 else if (!strcmp(class_name,"NSCalendarDate"))
538 {
539 Error error;
540 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
541 date_value = *((double*)&date_value_bits);
542 if (error.Fail())
543 return false;
544 }
545 else
546 {
547 if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
548 return false;
549 date_value = *((double*)&date_value_bits);
550 }
551 if (date_value == -63114076800)
552 {
553 stream.Printf("0001-12-30 00:00:00 +0000");
554 return true;
555 }
556 // this snippet of code assumes that time_t == seconds since Jan-1-1970
557 // this is generally true and POSIXly happy, but might break if a library
558 // vendor decides to get creative
559 time_t epoch = GetOSXEpoch();
560 epoch = epoch + (time_t)date_value;
Enrico Granatadb2ecad2014-10-15 20:18:58 +0000561 tm *tm_date = gmtime(&epoch);
Enrico Granata92373532013-03-19 22:58:48 +0000562 if (!tm_date)
563 return false;
564 std::string buffer(1024,0);
565 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
566 return false;
567 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());
568 return true;
569}
Enrico Granatad87cc312015-09-03 01:29:42 +0000570
571bool
572lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
573{
574 ProcessSP process_sp = valobj.GetProcessSP();
575 if (!process_sp)
576 return false;
577
578 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
579
580 if (!runtime)
581 return false;
582
583 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
584
585 if (!descriptor.get() || !descriptor->IsValid())
586 return false;
587
Enrico Granata7de855c2015-10-02 20:59:58 +0000588 ConstString class_name = descriptor->GetClassName();
Enrico Granatad87cc312015-09-03 01:29:42 +0000589
Enrico Granata7de855c2015-10-02 20:59:58 +0000590 if (class_name.IsEmpty())
Enrico Granatad87cc312015-09-03 01:29:42 +0000591 return false;
592
Enrico Granata7de855c2015-10-02 20:59:58 +0000593 if (ConstString cs = Mangled(class_name).GetDemangledName(lldb::eLanguageTypeUnknown))
594 class_name = cs;
595
596 stream.Printf("%s",class_name.AsCString("<unknown class>"));
Enrico Granatad87cc312015-09-03 01:29:42 +0000597 return true;
598}
599
600class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd
601{
602public:
603 ObjCClassSyntheticChildrenFrontEnd (lldb::ValueObjectSP valobj_sp) :
604 SyntheticChildrenFrontEnd(*valobj_sp.get())
605 {
606 }
607
608 virtual size_t
609 CalculateNumChildren ()
610 {
611 return 0;
612 }
613
614 virtual lldb::ValueObjectSP
615 GetChildAtIndex (size_t idx)
616 {
617 return lldb::ValueObjectSP();
618 }
619
620 virtual bool
621 Update()
622 {
623 return false;
624 }
625
626 virtual bool
627 MightHaveChildren ()
628 {
629 return false;
630 }
631
632 virtual size_t
633 GetIndexOfChildWithName (const ConstString &name)
634 {
635 return UINT32_MAX;
636 }
637
638 virtual
639 ~ObjCClassSyntheticChildrenFrontEnd ()
640 {
641 }
642};
643
644SyntheticChildrenFrontEnd*
645lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
646{
647 return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
648}
649
650template<bool needs_at>
651bool
652lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
653{
654 ProcessSP process_sp = valobj.GetProcessSP();
655 if (!process_sp)
656 return false;
657
658 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
659
660 if (!runtime)
661 return false;
662
663 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
664
665 if (!descriptor.get() || !descriptor->IsValid())
666 return false;
667
668 bool is_64bit = (process_sp->GetAddressByteSize() == 8);
669 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
670
671 if (!valobj_addr)
672 return false;
673
674 uint64_t value = 0;
675
676 const char* class_name = descriptor->GetClassName().GetCString();
677
678 if (!class_name || !*class_name)
679 return false;
680
681 if (!strcmp(class_name,"NSConcreteData") ||
682 !strcmp(class_name,"NSConcreteMutableData") ||
683 !strcmp(class_name,"__NSCFData"))
684 {
685 uint32_t offset = (is_64bit ? 16 : 8);
686 Error error;
687 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
688 if (error.Fail())
689 return false;
690 }
691 else
692 {
693 if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
694 return false;
695 }
696
697 stream.Printf("%s%" PRIu64 " byte%s%s",
698 (needs_at ? "@\"" : ""),
699 value,
700 (value != 1 ? "s" : ""),
701 (needs_at ? "\"" : ""));
702
703 return true;
704}
705
706bool
Enrico Granatad87cc312015-09-03 01:29:42 +0000707lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
708{
709 const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();
710
711 ValueObjectSP real_guy_sp = valobj.GetSP();
712
713 if (type_info & eTypeIsPointer)
714 {
715 Error err;
716 real_guy_sp = valobj.Dereference(err);
717 if (err.Fail() || !real_guy_sp)
718 return false;
719 }
720 else if (type_info & eTypeIsReference)
721 {
722 real_guy_sp = valobj.GetChildAtIndex(0, true);
723 if (!real_guy_sp)
724 return false;
725 }
726 uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
727 if (value == 0)
728 {
729 stream.Printf("NO");
730 return true;
731 }
732 stream.Printf("YES");
733 return true;
734}
735
736template <bool is_sel_ptr>
737bool
738lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
739{
740 lldb::ValueObjectSP valobj_sp;
741
742 CompilerType charstar (valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeChar).GetPointerType());
743
744 if (!charstar)
745 return false;
746
747 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
748
749 if (is_sel_ptr)
750 {
751 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
752 if (data_address == LLDB_INVALID_ADDRESS)
753 return false;
754 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar);
755 }
756 else
757 {
758 DataExtractor data;
759 Error error;
760 valobj.GetData(data, error);
761 if (error.Fail())
762 return false;
763 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
764 }
765
766 if (!valobj_sp)
767 return false;
768
769 stream.Printf("%s",valobj_sp->GetSummaryAsCString());
770 return true;
771}
772
773// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
774// this call gives the POSIX equivalent of the Cocoa epoch
775time_t
776lldb_private::formatters::GetOSXEpoch ()
777{
778 static time_t epoch = 0;
779 if (!epoch)
780 {
781#ifndef _WIN32
782 tzset();
783 tm tm_epoch;
784 tm_epoch.tm_sec = 0;
785 tm_epoch.tm_hour = 0;
786 tm_epoch.tm_min = 0;
787 tm_epoch.tm_mon = 0;
788 tm_epoch.tm_mday = 1;
789 tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why.
790 tm_epoch.tm_isdst = -1;
791 tm_epoch.tm_gmtoff = 0;
792 tm_epoch.tm_zone = NULL;
793 epoch = timegm(&tm_epoch);
794#endif
795 }
796 return epoch;
797}
798
Enrico Granata419d7912015-09-04 00:33:51 +0000799bool
800lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
801{
802 stream.Printf("%s",valobj.GetObjectDescription());
803 return true;
804}
805
Enrico Granatad87cc312015-09-03 01:29:42 +0000806template bool
807lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
808
809template bool
810lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
811
812template bool
813lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
814
815template bool
816lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ;