blob: 5396aea4422f366346f0789bbd081d7a6264bdb4 [file] [log] [blame]
Eugene Zelenko8d15f332015-10-20 01:10:59 +00001//===-- Cocoa.cpp -----------------------------------------------*- C++ -*-===//
Enrico Granata92373532013-03-19 22:58:48 +00002//
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
Eugene Zelenko8d15f332015-10-20 01:10:59 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
Enrico Granata170c3952015-09-14 22:18:32 +000014#include "Cocoa.h"
Enrico Granata92373532013-03-19 22:58:48 +000015
16#include "lldb/Core/DataBufferHeap.h"
17#include "lldb/Core/Error.h"
Enrico Granata7de855c2015-10-02 20:59:58 +000018#include "lldb/Core/Mangled.h"
Enrico Granata92373532013-03-19 22:58:48 +000019#include "lldb/Core/Stream.h"
20#include "lldb/Core/ValueObject.h"
21#include "lldb/Core/ValueObjectConstResult.h"
Enrico Granata419d7912015-09-04 00:33:51 +000022#include "lldb/DataFormatters/FormattersHelpers.h"
23#include "lldb/DataFormatters/StringPrinter.h"
24#include "lldb/DataFormatters/TypeSummary.h"
Enrico Granata92373532013-03-19 22:58:48 +000025#include "lldb/Host/Endian.h"
Pavel Labath46897a42017-01-25 11:19:49 +000026#include "lldb/Host/Time.h"
Enrico Granata92373532013-03-19 22:58:48 +000027#include "lldb/Symbol/ClangASTContext.h"
Enrico Granata675f49b2015-10-07 18:36:53 +000028#include "lldb/Target/Language.h"
Enrico Granata92373532013-03-19 22:58:48 +000029#include "lldb/Target/ObjCLanguageRuntime.h"
Enrico Granata419d7912015-09-04 00:33:51 +000030#include "lldb/Target/Process.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000031#include "lldb/Target/Target.h"
Enrico Granatad87cc312015-09-03 01:29:42 +000032#include "lldb/Utility/ProcessStructReader.h"
33
Enrico Granata2094e442016-08-22 18:07:52 +000034#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
35
Enrico Granata7de855c2015-10-02 20:59:58 +000036#include "NSString.h"
37
Enrico Granata92373532013-03-19 22:58:48 +000038using namespace lldb;
39using namespace lldb_private;
40using namespace lldb_private::formatters;
41
Kate Stoneb9c1b512016-09-06 20:57:50 +000042bool lldb_private::formatters::NSBundleSummaryProvider(
43 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
44 ProcessSP process_sp = valobj.GetProcessSP();
45 if (!process_sp)
Enrico Granataaa05cf92016-04-01 20:33:22 +000046 return false;
Enrico Granata92373532013-03-19 22:58:48 +000047
Kate Stoneb9c1b512016-09-06 20:57:50 +000048 ObjCLanguageRuntime *runtime =
49 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
50 lldb::eLanguageTypeObjC);
51
52 if (!runtime)
Enrico Granataaa05cf92016-04-01 20:33:22 +000053 return false;
Enrico Granata92373532013-03-19 22:58:48 +000054
Kate Stoneb9c1b512016-09-06 20:57:50 +000055 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
56 runtime->GetClassDescriptor(valobj));
57
58 if (!descriptor || !descriptor->IsValid())
Enrico Granataaa05cf92016-04-01 20:33:22 +000059 return false;
Enrico Granata92373532013-03-19 22:58:48 +000060
Kate Stoneb9c1b512016-09-06 20:57:50 +000061 uint32_t ptr_size = process_sp->GetAddressByteSize();
62
63 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
64
65 if (!valobj_addr)
Enrico Granataaa05cf92016-04-01 20:33:22 +000066 return false;
Enrico Granata92373532013-03-19 22:58:48 +000067
Kate Stoneb9c1b512016-09-06 20:57:50 +000068 const char *class_name = descriptor->GetClassName().GetCString();
Enrico Granata92373532013-03-19 22:58:48 +000069
Kate Stoneb9c1b512016-09-06 20:57:50 +000070 if (!class_name || !*class_name)
Enrico Granataaa05cf92016-04-01 20:33:22 +000071 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +000072
73 if (!strcmp(class_name, "NSBundle")) {
74 uint64_t offset = 5 * ptr_size;
75 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
76 offset,
77 valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID),
78 true));
79
80 StreamString summary_stream;
81 bool was_nsstring_ok =
82 NSStringSummaryProvider(*text, summary_stream, options);
83 if (was_nsstring_ok && summary_stream.GetSize() > 0) {
84 stream.Printf("%s", summary_stream.GetData());
85 return true;
86 }
87 }
88
89 return false;
Enrico Granata92373532013-03-19 22:58:48 +000090}
91
Kate Stoneb9c1b512016-09-06 20:57:50 +000092bool lldb_private::formatters::NSTimeZoneSummaryProvider(
93 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
94 ProcessSP process_sp = valobj.GetProcessSP();
95 if (!process_sp)
Enrico Granata92373532013-03-19 22:58:48 +000096 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +000097
98 ObjCLanguageRuntime *runtime =
99 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
100 lldb::eLanguageTypeObjC);
101
102 if (!runtime)
103 return false;
104
105 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
106 runtime->GetClassDescriptor(valobj));
107
108 if (!descriptor || !descriptor->IsValid())
109 return false;
110
111 uint32_t ptr_size = process_sp->GetAddressByteSize();
112
113 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
114
115 if (!valobj_addr)
116 return false;
117
118 const char *class_name = descriptor->GetClassName().GetCString();
119
120 if (!class_name || !*class_name)
121 return false;
122
123 if (!strcmp(class_name, "__NSTimeZone")) {
124 uint64_t offset = ptr_size;
125 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
126 offset, valobj.GetCompilerType(), true));
127 StreamString summary_stream;
128 bool was_nsstring_ok =
129 NSStringSummaryProvider(*text, summary_stream, options);
130 if (was_nsstring_ok && summary_stream.GetSize() > 0) {
131 stream.Printf("%s", summary_stream.GetData());
132 return true;
133 }
134 }
135
136 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000137}
138
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139bool lldb_private::formatters::NSNotificationSummaryProvider(
140 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
141 ProcessSP process_sp = valobj.GetProcessSP();
142 if (!process_sp)
143 return false;
Enrico Granataaa05cf92016-04-01 20:33:22 +0000144
Kate Stoneb9c1b512016-09-06 20:57:50 +0000145 ObjCLanguageRuntime *runtime =
146 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
147 lldb::eLanguageTypeObjC);
148
149 if (!runtime)
150 return false;
151
152 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
153 runtime->GetClassDescriptor(valobj));
154
155 if (!descriptor || !descriptor->IsValid())
156 return false;
157
158 uint32_t ptr_size = process_sp->GetAddressByteSize();
159
160 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
161
162 if (!valobj_addr)
163 return false;
164
165 const char *class_name = descriptor->GetClassName().GetCString();
166
167 if (!class_name || !*class_name)
168 return false;
169
170 if (!strcmp(class_name, "NSConcreteNotification")) {
171 uint64_t offset = ptr_size;
172 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
173 offset, valobj.GetCompilerType(), true));
174 StreamString summary_stream;
175 bool was_nsstring_ok =
176 NSStringSummaryProvider(*text, summary_stream, options);
177 if (was_nsstring_ok && summary_stream.GetSize() > 0) {
178 stream.Printf("%s", summary_stream.GetData());
179 return true;
Enrico Granata92373532013-03-19 22:58:48 +0000180 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181 }
182
183 return false;
184}
185
186bool lldb_private::formatters::NSMachPortSummaryProvider(
187 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
188 ProcessSP process_sp = valobj.GetProcessSP();
189 if (!process_sp)
190 return false;
191
192 ObjCLanguageRuntime *runtime =
193 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
194 lldb::eLanguageTypeObjC);
195
196 if (!runtime)
197 return false;
198
199 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
200 runtime->GetClassDescriptor(valobj));
201
202 if (!descriptor || !descriptor->IsValid())
203 return false;
204
205 uint32_t ptr_size = process_sp->GetAddressByteSize();
206
207 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
208
209 if (!valobj_addr)
210 return false;
211
212 const char *class_name = descriptor->GetClassName().GetCString();
213
214 if (!class_name || !*class_name)
215 return false;
216
217 uint64_t port_number = 0;
218
219 if (!strcmp(class_name, "NSMachPort")) {
220 uint64_t offset = (ptr_size == 4 ? 12 : 20);
221 Error error;
222 port_number = process_sp->ReadUnsignedIntegerFromMemory(
223 offset + valobj_addr, 4, 0, error);
224 if (error.Success()) {
225 stream.Printf("mach port: %u",
226 (uint32_t)(port_number & 0x00000000FFFFFFFF));
227 return true;
228 }
229 }
230
231 return false;
232}
233
234bool lldb_private::formatters::NSIndexSetSummaryProvider(
235 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
236 ProcessSP process_sp = valobj.GetProcessSP();
237 if (!process_sp)
238 return false;
239
240 ObjCLanguageRuntime *runtime =
241 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
242 lldb::eLanguageTypeObjC);
243
244 if (!runtime)
245 return false;
246
247 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
248 runtime->GetClassDescriptor(valobj));
249
250 if (!descriptor || !descriptor->IsValid())
251 return false;
252
253 uint32_t ptr_size = process_sp->GetAddressByteSize();
254
255 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
256
257 if (!valobj_addr)
258 return false;
259
260 const char *class_name = descriptor->GetClassName().GetCString();
261
262 if (!class_name || !*class_name)
263 return false;
264
265 uint64_t count = 0;
266
267 do {
268 if (!strcmp(class_name, "NSIndexSet") ||
269 !strcmp(class_name, "NSMutableIndexSet")) {
270 Error error;
271 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(
272 valobj_addr + ptr_size, 4, 0, error);
273 if (error.Fail())
274 return false;
275 // this means the set is empty - count = 0
276 if ((mode & 1) == 1) {
277 count = 0;
278 break;
279 }
280 if ((mode & 2) == 2)
281 mode = 1; // this means the set only has one range
282 else
283 mode = 2; // this means the set has multiple ranges
284 if (mode == 1) {
285 count = process_sp->ReadUnsignedIntegerFromMemory(
286 valobj_addr + 3 * ptr_size, ptr_size, 0, error);
Enrico Granata92373532013-03-19 22:58:48 +0000287 if (error.Fail())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000288 return false;
289 } else {
290 // read a pointer to the data at 2*ptr_size
291 count = process_sp->ReadUnsignedIntegerFromMemory(
292 valobj_addr + 2 * ptr_size, ptr_size, 0, error);
293 if (error.Fail())
294 return false;
295 // read the data at 2*ptr_size from the first location
296 count = process_sp->ReadUnsignedIntegerFromMemory(count + 2 * ptr_size,
297 ptr_size, 0, error);
298 if (error.Fail())
299 return false;
300 }
301 } else
302 return false;
303 } while (false);
304 stream.Printf("%" PRIu64 " index%s", count, (count == 1 ? "" : "es"));
305 return true;
Enrico Granata92373532013-03-19 22:58:48 +0000306}
Enrico Granatad87cc312015-09-03 01:29:42 +0000307
Kate Stoneb9c1b512016-09-06 20:57:50 +0000308static void NSNumber_FormatChar(ValueObject &valobj, Stream &stream, char value,
309 lldb::LanguageType lang) {
310 static ConstString g_TypeHint("NSNumber:char");
311
312 std::string prefix, suffix;
313 if (Language *language = Language::FindPlugin(lang)) {
314 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
315 suffix)) {
316 prefix.clear();
317 suffix.clear();
318 }
319 }
320
321 stream.Printf("%s%hhd%s", prefix.c_str(), value, suffix.c_str());
Enrico Granatad87cc312015-09-03 01:29:42 +0000322}
323
Kate Stoneb9c1b512016-09-06 20:57:50 +0000324static void NSNumber_FormatShort(ValueObject &valobj, Stream &stream,
325 short value, lldb::LanguageType lang) {
326 static ConstString g_TypeHint("NSNumber:short");
327
328 std::string prefix, suffix;
329 if (Language *language = Language::FindPlugin(lang)) {
330 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
331 suffix)) {
332 prefix.clear();
333 suffix.clear();
334 }
335 }
336
337 stream.Printf("%s%hd%s", prefix.c_str(), value, suffix.c_str());
338}
339
340static void NSNumber_FormatInt(ValueObject &valobj, Stream &stream, int value,
341 lldb::LanguageType lang) {
342 static ConstString g_TypeHint("NSNumber:int");
343
344 std::string prefix, suffix;
345 if (Language *language = Language::FindPlugin(lang)) {
346 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
347 suffix)) {
348 prefix.clear();
349 suffix.clear();
350 }
351 }
352
353 stream.Printf("%s%d%s", prefix.c_str(), value, suffix.c_str());
354}
355
356static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream,
357 uint64_t value, lldb::LanguageType lang) {
358 static ConstString g_TypeHint("NSNumber:long");
359
360 std::string prefix, suffix;
361 if (Language *language = Language::FindPlugin(lang)) {
362 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
363 suffix)) {
364 prefix.clear();
365 suffix.clear();
366 }
367 }
368
369 stream.Printf("%s%" PRId64 "%s", prefix.c_str(), value, suffix.c_str());
370}
371
372static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream,
373 float value, lldb::LanguageType lang) {
374 static ConstString g_TypeHint("NSNumber:float");
375
376 std::string prefix, suffix;
377 if (Language *language = Language::FindPlugin(lang)) {
378 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
379 suffix)) {
380 prefix.clear();
381 suffix.clear();
382 }
383 }
384
385 stream.Printf("%s%f%s", prefix.c_str(), value, suffix.c_str());
386}
387
388static void NSNumber_FormatDouble(ValueObject &valobj, Stream &stream,
389 double value, lldb::LanguageType lang) {
390 static ConstString g_TypeHint("NSNumber:double");
391
392 std::string prefix, suffix;
393 if (Language *language = Language::FindPlugin(lang)) {
394 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
395 suffix)) {
396 prefix.clear();
397 suffix.clear();
398 }
399 }
400
401 stream.Printf("%s%g%s", prefix.c_str(), value, suffix.c_str());
402}
403
404bool lldb_private::formatters::NSNumberSummaryProvider(
405 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
406 ProcessSP process_sp = valobj.GetProcessSP();
407 if (!process_sp)
408 return false;
409
410 ObjCLanguageRuntime *runtime =
411 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
412 lldb::eLanguageTypeObjC);
413
414 if (!runtime)
415 return false;
416
417 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
418 runtime->GetClassDescriptor(valobj));
419
420 if (!descriptor || !descriptor->IsValid())
421 return false;
422
423 uint32_t ptr_size = process_sp->GetAddressByteSize();
424
425 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
426
427 if (!valobj_addr)
428 return false;
429
430 const char *class_name = descriptor->GetClassName().GetCString();
431
432 if (!class_name || !*class_name)
433 return false;
434
435 if (!strcmp(class_name, "__NSCFBoolean"))
436 return ObjCBooleanSummaryProvider(valobj, stream, options);
437
438 if (!strcmp(class_name, "NSNumber") || !strcmp(class_name, "__NSCFNumber")) {
439 uint64_t value = 0;
440 uint64_t i_bits = 0;
441 if (descriptor->GetTaggedPointerInfo(&i_bits, &value)) {
442 switch (i_bits) {
443 case 0:
444 NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
445 break;
446 case 1:
447 case 4:
448 NSNumber_FormatShort(valobj, stream, (short)value,
449 options.GetLanguage());
450 break;
451 case 2:
452 case 8:
453 NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
454 break;
455 case 3:
456 case 12:
457 NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
458 break;
459 default:
460 return false;
461 }
462 return true;
463 } else {
464 Error error;
465 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(
466 valobj_addr + ptr_size, 1, 0, error) &
467 0x1F);
468 uint64_t data_location = valobj_addr + 2 * ptr_size;
469 uint64_t value = 0;
470 if (error.Fail())
471 return false;
472 switch (data_type) {
473 case 1: // 0B00001
474 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0,
475 error);
476 if (error.Fail())
477 return false;
478 NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
479 break;
480 case 2: // 0B0010
481 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0,
482 error);
483 if (error.Fail())
484 return false;
485 NSNumber_FormatShort(valobj, stream, (short)value,
486 options.GetLanguage());
487 break;
488 case 3: // 0B0011
489 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0,
490 error);
491 if (error.Fail())
492 return false;
493 NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
494 break;
495 case 17: // 0B10001
496 data_location += 8;
497 LLVM_FALLTHROUGH;
498 case 4: // 0B0100
499 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0,
500 error);
501 if (error.Fail())
502 return false;
503 NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
504 break;
505 case 5: // 0B0101
506 {
507 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
508 data_location, 4, 0, error);
509 if (error.Fail())
510 return false;
511 float flt_value = 0.0f;
512 memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int));
513 NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
514 break;
515 }
516 case 6: // 0B0110
517 {
518 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
519 data_location, 8, 0, error);
520 if (error.Fail())
521 return false;
522 double dbl_value = 0.0;
523 memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng));
524 NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
525 break;
526 }
527 default:
528 return false;
529 }
530 return true;
531 }
532 }
533
534 return false;
535}
536
537bool lldb_private::formatters::NSURLSummaryProvider(
538 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
539 ProcessSP process_sp = valobj.GetProcessSP();
540 if (!process_sp)
541 return false;
542
543 ObjCLanguageRuntime *runtime =
544 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
545 lldb::eLanguageTypeObjC);
546
547 if (!runtime)
548 return false;
549
550 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
551 runtime->GetClassDescriptor(valobj));
552
553 if (!descriptor || !descriptor->IsValid())
554 return false;
555
556 uint32_t ptr_size = process_sp->GetAddressByteSize();
557
558 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
559
560 if (!valobj_addr)
561 return false;
562
Zachary Turner2dd214a2016-11-15 20:13:14 +0000563 llvm::StringRef class_name = descriptor->GetClassName().GetStringRef();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000564
Zachary Turner2dd214a2016-11-15 20:13:14 +0000565 if (!class_name.equals("NSURL"))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000566 return false;
567
Zachary Turner2dd214a2016-11-15 20:13:14 +0000568 uint64_t offset_text = ptr_size + ptr_size +
569 8; // ISA + pointer + 8 bytes of data (even on 32bit)
570 uint64_t offset_base = offset_text + ptr_size;
571 CompilerType type(valobj.GetCompilerType());
572 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
573 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
574 if (!text)
575 return false;
576 if (text->GetValueAsUnsigned(0) == 0)
577 return false;
578 StreamString summary;
579 if (!NSStringSummaryProvider(*text, summary, options))
580 return false;
581 if (base && base->GetValueAsUnsigned(0)) {
582 std::string summary_str = summary.GetString();
583
584 if (!summary_str.empty())
585 summary_str.pop_back();
586 summary_str += " -- ";
587 StreamString base_summary;
588 if (NSURLSummaryProvider(*base, base_summary, options) &&
589 !base_summary.Empty()) {
590 llvm::StringRef base_str = base_summary.GetString();
591 if (base_str.size() > 2)
592 base_str = base_str.drop_front(2);
593 summary_str += base_str;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000594 }
Zachary Turner2dd214a2016-11-15 20:13:14 +0000595 summary.Clear();
596 summary.PutCString(summary_str);
597 }
598 if (!summary.Empty()) {
599 stream.PutCString(summary.GetString());
600 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000601 }
602
603 return false;
604}
605
606bool lldb_private::formatters::NSDateSummaryProvider(
607 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
608 ProcessSP process_sp = valobj.GetProcessSP();
609 if (!process_sp)
610 return false;
611
612 ObjCLanguageRuntime *runtime =
613 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
614 lldb::eLanguageTypeObjC);
615
616 if (!runtime)
617 return false;
618
619 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
620 runtime->GetClassDescriptor(valobj));
621
622 if (!descriptor || !descriptor->IsValid())
623 return false;
624
625 uint32_t ptr_size = process_sp->GetAddressByteSize();
626
627 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
628
629 if (!valobj_addr)
630 return false;
631
632 uint64_t date_value_bits = 0;
633 double date_value = 0.0;
634
635 ConstString class_name = descriptor->GetClassName();
636
637 static const ConstString g_NSDate("NSDate");
638 static const ConstString g___NSDate("__NSDate");
639 static const ConstString g___NSTaggedDate("__NSTaggedDate");
640 static const ConstString g_NSCalendarDate("NSCalendarDate");
641
642 if (class_name.IsEmpty())
643 return false;
644
645 if ((class_name == g_NSDate) || (class_name == g___NSDate) ||
646 (class_name == g___NSTaggedDate)) {
647 uint64_t info_bits = 0, value_bits = 0;
648 if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits)) {
649 date_value_bits = ((value_bits << 8) | (info_bits << 4));
650 memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
651 } else {
652 llvm::Triple triple(
653 process_sp->GetTarget().GetArchitecture().GetTriple());
654 uint32_t delta =
655 (triple.isWatchOS() && triple.isWatchABI()) ? 8 : ptr_size;
656 Error error;
657 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
658 valobj_addr + delta, 8, 0, error);
659 memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
660 if (error.Fail())
661 return false;
662 }
663 } else if (class_name == g_NSCalendarDate) {
664 Error error;
665 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
666 valobj_addr + 2 * ptr_size, 8, 0, error);
667 memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
668 if (error.Fail())
669 return false;
670 } else
671 return false;
672
673 if (date_value == -63114076800) {
674 stream.Printf("0001-12-30 00:00:00 +0000");
675 return true;
676 }
677 // this snippet of code assumes that time_t == seconds since Jan-1-1970
678 // this is generally true and POSIXly happy, but might break if a library
679 // vendor decides to get creative
680 time_t epoch = GetOSXEpoch();
681 epoch = epoch + (time_t)date_value;
682 tm *tm_date = gmtime(&epoch);
683 if (!tm_date)
684 return false;
685 std::string buffer(1024, 0);
686 if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
687 return false;
688 stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
689 tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
690 tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
691 return true;
692}
693
694bool lldb_private::formatters::ObjCClassSummaryProvider(
695 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
696 ProcessSP process_sp = valobj.GetProcessSP();
697 if (!process_sp)
698 return false;
699
700 ObjCLanguageRuntime *runtime =
701 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
702 lldb::eLanguageTypeObjC);
703
704 if (!runtime)
705 return false;
706
707 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
708 runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
709
710 if (!descriptor || !descriptor->IsValid())
711 return false;
712
713 ConstString class_name = descriptor->GetClassName();
714
715 if (class_name.IsEmpty())
716 return false;
717
718 if (ConstString cs =
719 Mangled(class_name).GetDemangledName(lldb::eLanguageTypeUnknown))
720 class_name = cs;
721
722 stream.Printf("%s", class_name.AsCString("<unknown class>"));
723 return true;
724}
725
726class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd {
Enrico Granatad87cc312015-09-03 01:29:42 +0000727public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000728 ObjCClassSyntheticChildrenFrontEnd(lldb::ValueObjectSP valobj_sp)
729 : SyntheticChildrenFrontEnd(*valobj_sp) {}
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000730
Kate Stoneb9c1b512016-09-06 20:57:50 +0000731 ~ObjCClassSyntheticChildrenFrontEnd() override = default;
732
733 size_t CalculateNumChildren() override { return 0; }
734
735 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
736 return lldb::ValueObjectSP();
737 }
738
739 bool Update() override { return false; }
740
741 bool MightHaveChildren() override { return false; }
742
743 size_t GetIndexOfChildWithName(const ConstString &name) override {
744 return UINT32_MAX;
745 }
Enrico Granatad87cc312015-09-03 01:29:42 +0000746};
747
Kate Stoneb9c1b512016-09-06 20:57:50 +0000748SyntheticChildrenFrontEnd *
749lldb_private::formatters::ObjCClassSyntheticFrontEndCreator(
750 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
751 return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
Enrico Granatad87cc312015-09-03 01:29:42 +0000752}
753
Kate Stoneb9c1b512016-09-06 20:57:50 +0000754template <bool needs_at>
755bool lldb_private::formatters::NSDataSummaryProvider(
756 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
757 ProcessSP process_sp = valobj.GetProcessSP();
758 if (!process_sp)
Enrico Granata2094e442016-08-22 18:07:52 +0000759 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000760
761 ObjCLanguageRuntime *runtime =
762 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
763 lldb::eLanguageTypeObjC);
764
765 if (!runtime)
766 return false;
767
768 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
769 runtime->GetClassDescriptor(valobj));
770
771 if (!descriptor || !descriptor->IsValid())
772 return false;
773
774 bool is_64bit = (process_sp->GetAddressByteSize() == 8);
775 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
776
777 if (!valobj_addr)
778 return false;
779
780 uint64_t value = 0;
781
782 const char *class_name = descriptor->GetClassName().GetCString();
783
784 if (!class_name || !*class_name)
785 return false;
786
787 if (!strcmp(class_name, "NSConcreteData") ||
788 !strcmp(class_name, "NSConcreteMutableData") ||
789 !strcmp(class_name, "__NSCFData")) {
790 uint32_t offset = (is_64bit ? 16 : 8);
791 Error error;
792 value = process_sp->ReadUnsignedIntegerFromMemory(
793 valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
794 if (error.Fail())
795 return false;
796 } else if (!strcmp(class_name, "_NSInlineData")) {
797 uint32_t offset = (is_64bit ? 8 : 4);
798 Error error;
799 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, 2,
800 0, error);
801 if (error.Fail())
802 return false;
803 } else if (!strcmp(class_name, "_NSZeroData")) {
804 value = 0;
805 } else
806 return false;
807
808 stream.Printf("%s%" PRIu64 " byte%s%s", (needs_at ? "@\"" : ""), value,
809 (value != 1 ? "s" : ""), (needs_at ? "\"" : ""));
810
811 return true;
812}
813
814bool lldb_private::formatters::ObjCBOOLSummaryProvider(
815 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
816 const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();
817
818 ValueObjectSP real_guy_sp = valobj.GetSP();
819
820 if (type_info & eTypeIsPointer) {
821 Error err;
822 real_guy_sp = valobj.Dereference(err);
823 if (err.Fail() || !real_guy_sp)
824 return false;
825 } else if (type_info & eTypeIsReference) {
826 real_guy_sp = valobj.GetChildAtIndex(0, true);
827 if (!real_guy_sp)
828 return false;
829 }
830 uint8_t value = (real_guy_sp->GetValueAsUnsigned(0) & 0xFF);
831 switch (value) {
832 case 0:
833 stream.Printf("NO");
834 break;
835 case 1:
836 stream.Printf("YES");
837 break;
838 default:
839 stream.Printf("%u", value);
840 break;
841 }
842 return true;
843}
844
845bool lldb_private::formatters::ObjCBooleanSummaryProvider(
846 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
847 lldb::addr_t valobj_ptr_value =
848 valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
849 if (valobj_ptr_value == LLDB_INVALID_ADDRESS)
850 return false;
851
852 ProcessSP process_sp(valobj.GetProcessSP());
853 if (!process_sp)
854 return false;
855
856 if (AppleObjCRuntime *objc_runtime =
857 (AppleObjCRuntime *)process_sp->GetObjCLanguageRuntime()) {
858 lldb::addr_t cf_true = LLDB_INVALID_ADDRESS,
859 cf_false = LLDB_INVALID_ADDRESS;
860 objc_runtime->GetValuesForGlobalCFBooleans(cf_true, cf_false);
861 if (valobj_ptr_value == cf_true) {
862 stream.PutCString("YES");
863 return true;
864 }
865 if (valobj_ptr_value == cf_false) {
866 stream.PutCString("NO");
867 return true;
868 }
869 }
870
871 return false;
Enrico Granata2094e442016-08-22 18:07:52 +0000872}
873
Enrico Granatad87cc312015-09-03 01:29:42 +0000874template <bool is_sel_ptr>
Kate Stoneb9c1b512016-09-06 20:57:50 +0000875bool lldb_private::formatters::ObjCSELSummaryProvider(
876 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
877 lldb::ValueObjectSP valobj_sp;
878
879 CompilerType charstar(valobj.GetCompilerType()
880 .GetBasicTypeFromAST(eBasicTypeChar)
881 .GetPointerType());
882
883 if (!charstar)
884 return false;
885
886 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
887
888 if (is_sel_ptr) {
889 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
890 if (data_address == LLDB_INVALID_ADDRESS)
891 return false;
892 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address,
893 exe_ctx, charstar);
894 } else {
895 DataExtractor data;
896 Error error;
897 valobj.GetData(data, error);
898 if (error.Fail())
899 return false;
900 valobj_sp =
901 ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
902 }
903
904 if (!valobj_sp)
905 return false;
906
907 stream.Printf("%s", valobj_sp->GetSummaryAsCString());
908 return true;
Enrico Granatad87cc312015-09-03 01:29:42 +0000909}
910
911// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
912// this call gives the POSIX equivalent of the Cocoa epoch
Kate Stoneb9c1b512016-09-06 20:57:50 +0000913time_t lldb_private::formatters::GetOSXEpoch() {
914 static time_t epoch = 0;
915 if (!epoch) {
Enrico Granatad87cc312015-09-03 01:29:42 +0000916#ifndef _WIN32
Kate Stoneb9c1b512016-09-06 20:57:50 +0000917 tzset();
918 tm tm_epoch;
919 tm_epoch.tm_sec = 0;
920 tm_epoch.tm_hour = 0;
921 tm_epoch.tm_min = 0;
922 tm_epoch.tm_mon = 0;
923 tm_epoch.tm_mday = 1;
924 tm_epoch.tm_year = 2001 - 1900;
925 tm_epoch.tm_isdst = -1;
926 tm_epoch.tm_gmtoff = 0;
927 tm_epoch.tm_zone = nullptr;
928 epoch = timegm(&tm_epoch);
Enrico Granatad87cc312015-09-03 01:29:42 +0000929#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000930 }
931 return epoch;
Enrico Granatad87cc312015-09-03 01:29:42 +0000932}
933
Kate Stoneb9c1b512016-09-06 20:57:50 +0000934template bool lldb_private::formatters::NSDataSummaryProvider<true>(
935 ValueObject &, Stream &, const TypeSummaryOptions &);
Enrico Granatad87cc312015-09-03 01:29:42 +0000936
Kate Stoneb9c1b512016-09-06 20:57:50 +0000937template bool lldb_private::formatters::NSDataSummaryProvider<false>(
938 ValueObject &, Stream &, const TypeSummaryOptions &);
Enrico Granatad87cc312015-09-03 01:29:42 +0000939
Kate Stoneb9c1b512016-09-06 20:57:50 +0000940template bool lldb_private::formatters::ObjCSELSummaryProvider<true>(
941 ValueObject &, Stream &, const TypeSummaryOptions &);
Enrico Granatad87cc312015-09-03 01:29:42 +0000942
Kate Stoneb9c1b512016-09-06 20:57:50 +0000943template bool lldb_private::formatters::ObjCSELSummaryProvider<false>(
944 ValueObject &, Stream &, const TypeSummaryOptions &);