]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
Copy libevent sources to contrib
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / Language / ObjC / Cocoa.cpp
1 //===-- 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 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "Cocoa.h"
15
16 #include "lldb/Core/Mangled.h"
17 #include "lldb/Core/ValueObject.h"
18 #include "lldb/Core/ValueObjectConstResult.h"
19 #include "lldb/DataFormatters/FormattersHelpers.h"
20 #include "lldb/DataFormatters/StringPrinter.h"
21 #include "lldb/DataFormatters/TypeSummary.h"
22 #include "lldb/Host/Time.h"
23 #include "lldb/Symbol/ClangASTContext.h"
24 #include "lldb/Target/Language.h"
25 #include "lldb/Target/ObjCLanguageRuntime.h"
26 #include "lldb/Target/Process.h"
27 #include "lldb/Target/ProcessStructReader.h"
28 #include "lldb/Target/Target.h"
29 #include "lldb/Utility/DataBufferHeap.h"
30 #include "lldb/Utility/Endian.h"
31 #include "lldb/Utility/Status.h"
32 #include "lldb/Utility/Stream.h"
33
34 #include "llvm/ADT/APInt.h"
35
36 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
37
38 #include "NSString.h"
39
40 using namespace lldb;
41 using namespace lldb_private;
42 using namespace lldb_private::formatters;
43
44 bool lldb_private::formatters::NSBundleSummaryProvider(
45     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
46   ProcessSP process_sp = valobj.GetProcessSP();
47   if (!process_sp)
48     return false;
49
50   ObjCLanguageRuntime *runtime =
51       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
52           lldb::eLanguageTypeObjC);
53
54   if (!runtime)
55     return false;
56
57   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
58       runtime->GetClassDescriptor(valobj));
59
60   if (!descriptor || !descriptor->IsValid())
61     return false;
62
63   uint32_t ptr_size = process_sp->GetAddressByteSize();
64
65   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
66
67   if (!valobj_addr)
68     return false;
69
70   const char *class_name = descriptor->GetClassName().GetCString();
71
72   if (!class_name || !*class_name)
73     return false;
74
75   if (!strcmp(class_name, "NSBundle")) {
76     uint64_t offset = 5 * ptr_size;
77     ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
78         offset,
79         valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID),
80         true));
81
82     StreamString summary_stream;
83     bool was_nsstring_ok =
84         NSStringSummaryProvider(*text, summary_stream, options);
85     if (was_nsstring_ok && summary_stream.GetSize() > 0) {
86       stream.Printf("%s", summary_stream.GetData());
87       return true;
88     }
89   }
90
91   return false;
92 }
93
94 bool lldb_private::formatters::NSTimeZoneSummaryProvider(
95     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
96   ProcessSP process_sp = valobj.GetProcessSP();
97   if (!process_sp)
98     return false;
99
100   ObjCLanguageRuntime *runtime =
101       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
102           lldb::eLanguageTypeObjC);
103
104   if (!runtime)
105     return false;
106
107   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
108       runtime->GetClassDescriptor(valobj));
109
110   if (!descriptor || !descriptor->IsValid())
111     return false;
112
113   uint32_t ptr_size = process_sp->GetAddressByteSize();
114
115   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
116
117   if (!valobj_addr)
118     return false;
119
120   const char *class_name = descriptor->GetClassName().GetCString();
121
122   if (!class_name || !*class_name)
123     return false;
124
125   if (!strcmp(class_name, "__NSTimeZone")) {
126     uint64_t offset = ptr_size;
127     ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
128         offset, valobj.GetCompilerType(), true));
129     StreamString summary_stream;
130     bool was_nsstring_ok =
131         NSStringSummaryProvider(*text, summary_stream, options);
132     if (was_nsstring_ok && summary_stream.GetSize() > 0) {
133       stream.Printf("%s", summary_stream.GetData());
134       return true;
135     }
136   }
137
138   return false;
139 }
140
141 bool lldb_private::formatters::NSNotificationSummaryProvider(
142     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
143   ProcessSP process_sp = valobj.GetProcessSP();
144   if (!process_sp)
145     return false;
146
147   ObjCLanguageRuntime *runtime =
148       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
149           lldb::eLanguageTypeObjC);
150
151   if (!runtime)
152     return false;
153
154   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
155       runtime->GetClassDescriptor(valobj));
156
157   if (!descriptor || !descriptor->IsValid())
158     return false;
159
160   uint32_t ptr_size = process_sp->GetAddressByteSize();
161
162   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
163
164   if (!valobj_addr)
165     return false;
166
167   const char *class_name = descriptor->GetClassName().GetCString();
168
169   if (!class_name || !*class_name)
170     return false;
171
172   if (!strcmp(class_name, "NSConcreteNotification")) {
173     uint64_t offset = ptr_size;
174     ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
175         offset, valobj.GetCompilerType(), true));
176     StreamString summary_stream;
177     bool was_nsstring_ok =
178         NSStringSummaryProvider(*text, summary_stream, options);
179     if (was_nsstring_ok && summary_stream.GetSize() > 0) {
180       stream.Printf("%s", summary_stream.GetData());
181       return true;
182     }
183   }
184
185   return false;
186 }
187
188 bool lldb_private::formatters::NSMachPortSummaryProvider(
189     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
190   ProcessSP process_sp = valobj.GetProcessSP();
191   if (!process_sp)
192     return false;
193
194   ObjCLanguageRuntime *runtime =
195       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
196           lldb::eLanguageTypeObjC);
197
198   if (!runtime)
199     return false;
200
201   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
202       runtime->GetClassDescriptor(valobj));
203
204   if (!descriptor || !descriptor->IsValid())
205     return false;
206
207   uint32_t ptr_size = process_sp->GetAddressByteSize();
208
209   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
210
211   if (!valobj_addr)
212     return false;
213
214   const char *class_name = descriptor->GetClassName().GetCString();
215
216   if (!class_name || !*class_name)
217     return false;
218
219   uint64_t port_number = 0;
220
221   if (!strcmp(class_name, "NSMachPort")) {
222     uint64_t offset = (ptr_size == 4 ? 12 : 20);
223     Status error;
224     port_number = process_sp->ReadUnsignedIntegerFromMemory(
225         offset + valobj_addr, 4, 0, error);
226     if (error.Success()) {
227       stream.Printf("mach port: %u",
228                     (uint32_t)(port_number & 0x00000000FFFFFFFF));
229       return true;
230     }
231   }
232
233   return false;
234 }
235
236 bool lldb_private::formatters::NSIndexSetSummaryProvider(
237     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
238   ProcessSP process_sp = valobj.GetProcessSP();
239   if (!process_sp)
240     return false;
241
242   ObjCLanguageRuntime *runtime =
243       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
244           lldb::eLanguageTypeObjC);
245
246   if (!runtime)
247     return false;
248
249   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
250       runtime->GetClassDescriptor(valobj));
251
252   if (!descriptor || !descriptor->IsValid())
253     return false;
254
255   uint32_t ptr_size = process_sp->GetAddressByteSize();
256
257   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
258
259   if (!valobj_addr)
260     return false;
261
262   const char *class_name = descriptor->GetClassName().GetCString();
263
264   if (!class_name || !*class_name)
265     return false;
266
267   uint64_t count = 0;
268
269   do {
270     if (!strcmp(class_name, "NSIndexSet") ||
271         !strcmp(class_name, "NSMutableIndexSet")) {
272       Status error;
273       uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(
274           valobj_addr + ptr_size, 4, 0, error);
275       if (error.Fail())
276         return false;
277       // this means the set is empty - count = 0
278       if ((mode & 1) == 1) {
279         count = 0;
280         break;
281       }
282       if ((mode & 2) == 2)
283         mode = 1; // this means the set only has one range
284       else
285         mode = 2; // this means the set has multiple ranges
286       if (mode == 1) {
287         count = process_sp->ReadUnsignedIntegerFromMemory(
288             valobj_addr + 3 * ptr_size, ptr_size, 0, error);
289         if (error.Fail())
290           return false;
291       } else {
292         // read a pointer to the data at 2*ptr_size
293         count = process_sp->ReadUnsignedIntegerFromMemory(
294             valobj_addr + 2 * ptr_size, ptr_size, 0, error);
295         if (error.Fail())
296           return false;
297         // read the data at 2*ptr_size from the first location
298         count = process_sp->ReadUnsignedIntegerFromMemory(count + 2 * ptr_size,
299                                                           ptr_size, 0, error);
300         if (error.Fail())
301           return false;
302       }
303     } else
304       return false;
305   } while (false);
306   stream.Printf("%" PRIu64 " index%s", count, (count == 1 ? "" : "es"));
307   return true;
308 }
309
310 static void NSNumber_FormatChar(ValueObject &valobj, Stream &stream, char value,
311                                 lldb::LanguageType lang) {
312   static ConstString g_TypeHint("NSNumber:char");
313
314   std::string prefix, suffix;
315   if (Language *language = Language::FindPlugin(lang)) {
316     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
317                                             suffix)) {
318       prefix.clear();
319       suffix.clear();
320     }
321   }
322
323   stream.Printf("%s%hhd%s", prefix.c_str(), value, suffix.c_str());
324 }
325
326 static void NSNumber_FormatShort(ValueObject &valobj, Stream &stream,
327                                  short value, lldb::LanguageType lang) {
328   static ConstString g_TypeHint("NSNumber:short");
329
330   std::string prefix, suffix;
331   if (Language *language = Language::FindPlugin(lang)) {
332     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
333                                             suffix)) {
334       prefix.clear();
335       suffix.clear();
336     }
337   }
338
339   stream.Printf("%s%hd%s", prefix.c_str(), value, suffix.c_str());
340 }
341
342 static void NSNumber_FormatInt(ValueObject &valobj, Stream &stream, int value,
343                                lldb::LanguageType lang) {
344   static ConstString g_TypeHint("NSNumber:int");
345
346   std::string prefix, suffix;
347   if (Language *language = Language::FindPlugin(lang)) {
348     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
349                                             suffix)) {
350       prefix.clear();
351       suffix.clear();
352     }
353   }
354
355   stream.Printf("%s%d%s", prefix.c_str(), value, suffix.c_str());
356 }
357
358 static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream,
359                                 uint64_t value, lldb::LanguageType lang) {
360   static ConstString g_TypeHint("NSNumber:long");
361
362   std::string prefix, suffix;
363   if (Language *language = Language::FindPlugin(lang)) {
364     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
365                                             suffix)) {
366       prefix.clear();
367       suffix.clear();
368     }
369   }
370
371   stream.Printf("%s%" PRId64 "%s", prefix.c_str(), value, suffix.c_str());
372 }
373
374 static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream,
375                                  const llvm::APInt &value,
376                                  lldb::LanguageType lang) {
377   static ConstString g_TypeHint("NSNumber:int128_t");
378   
379   std::string prefix, suffix;
380   if (Language *language = Language::FindPlugin(lang)) {
381     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
382                                             suffix)) {
383       prefix.clear();
384       suffix.clear();
385     }
386   }
387   
388   stream.PutCString(prefix.c_str());
389   const int radix = 10;
390   const bool isSigned = true;
391   std::string str = value.toString(radix, isSigned);
392   stream.PutCString(str.c_str());
393   stream.PutCString(suffix.c_str());
394 }
395
396 static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream,
397                                  float value, lldb::LanguageType lang) {
398   static ConstString g_TypeHint("NSNumber:float");
399
400   std::string prefix, suffix;
401   if (Language *language = Language::FindPlugin(lang)) {
402     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
403                                             suffix)) {
404       prefix.clear();
405       suffix.clear();
406     }
407   }
408
409   stream.Printf("%s%f%s", prefix.c_str(), value, suffix.c_str());
410 }
411
412 static void NSNumber_FormatDouble(ValueObject &valobj, Stream &stream,
413                                   double value, lldb::LanguageType lang) {
414   static ConstString g_TypeHint("NSNumber:double");
415
416   std::string prefix, suffix;
417   if (Language *language = Language::FindPlugin(lang)) {
418     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
419                                             suffix)) {
420       prefix.clear();
421       suffix.clear();
422     }
423   }
424
425   stream.Printf("%s%g%s", prefix.c_str(), value, suffix.c_str());
426 }
427
428 bool lldb_private::formatters::NSNumberSummaryProvider(
429     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
430   ProcessSP process_sp = valobj.GetProcessSP();
431   if (!process_sp)
432     return false;
433
434   ObjCLanguageRuntime *runtime =
435       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
436           lldb::eLanguageTypeObjC);
437
438   if (!runtime)
439     return false;
440
441   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
442       runtime->GetClassDescriptor(valobj));
443
444   if (!descriptor || !descriptor->IsValid())
445     return false;
446
447   uint32_t ptr_size = process_sp->GetAddressByteSize();
448
449   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
450
451   if (!valobj_addr)
452     return false;
453
454   const char *class_name = descriptor->GetClassName().GetCString();
455
456   if (!class_name || !*class_name)
457     return false;
458
459   if (!strcmp(class_name, "__NSCFBoolean"))
460     return ObjCBooleanSummaryProvider(valobj, stream, options);
461
462   if (!strcmp(class_name, "NSNumber") || !strcmp(class_name, "__NSCFNumber")) {
463     uint64_t value = 0;
464     uint64_t i_bits = 0;
465     if (descriptor->GetTaggedPointerInfo(&i_bits, &value)) {
466       switch (i_bits) {
467       case 0:
468         NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
469         break;
470       case 1:
471       case 4:
472         NSNumber_FormatShort(valobj, stream, (short)value,
473                              options.GetLanguage());
474         break;
475       case 2:
476       case 8:
477         NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
478         break;
479       case 3:
480       case 12:
481         NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
482         break;
483       default:
484         return false;
485       }
486       return true;
487     } else {
488       Status error;
489       
490       AppleObjCRuntime *runtime =
491       llvm::dyn_cast_or_null<AppleObjCRuntime>(
492           process_sp->GetObjCLanguageRuntime());
493
494       const bool new_format =
495           (runtime && runtime->GetFoundationVersion() >= 1400);
496
497       enum class TypeCodes : int {
498         sint8 = 0x0,
499         sint16 = 0x1,
500         sint32 = 0x2,
501         sint64 = 0x3,
502         f32 = 0x4,
503         f64 = 0x5,
504         sint128 = 0x6
505       };
506       
507       uint64_t data_location = valobj_addr + 2 * ptr_size;
508       TypeCodes type_code;
509       
510       if (new_format) {
511         uint64_t cfinfoa =
512             process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
513                                                       ptr_size, 0, error);
514         
515         if (error.Fail())
516           return false;
517
518         bool is_preserved_number = cfinfoa & 0x8;
519         if (is_preserved_number) {
520           lldbassert(!static_cast<bool>("We should handle preserved numbers!"));
521           return false;
522         }
523
524         type_code = static_cast<TypeCodes>(cfinfoa & 0x7);
525       } else {
526         uint8_t data_type =
527         process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1,
528                                                   0, error) & 0x1F;
529         
530         if (error.Fail())
531           return false;
532         
533         switch (data_type) {
534           case 1: type_code = TypeCodes::sint8; break;
535           case 2: type_code = TypeCodes::sint16; break;
536           case 3: type_code = TypeCodes::sint32; break;
537           case 17: data_location += 8; LLVM_FALLTHROUGH;
538           case 4: type_code = TypeCodes::sint64; break;
539           case 5: type_code = TypeCodes::f32; break;
540           case 6: type_code = TypeCodes::f64; break;
541           default: return false;
542         }
543       }
544       
545       uint64_t value = 0;
546       bool success = false;
547       switch (type_code) {
548         case TypeCodes::sint8:
549         value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0,
550                                                           error);
551         if (error.Fail())
552           return false;
553         NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
554         success = true;
555         break;
556         case TypeCodes::sint16:
557         value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0,
558                                                           error);
559         if (error.Fail())
560           return false;
561         NSNumber_FormatShort(valobj, stream, (short)value,
562                              options.GetLanguage());
563         success = true;
564         break;
565       case TypeCodes::sint32:
566         value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0,
567                                                           error);
568         if (error.Fail())
569           return false;
570         NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
571         success = true;
572         break;
573       case TypeCodes::sint64:
574         value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0,
575                                                           error);
576         if (error.Fail())
577           return false;
578         NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
579         success = true;
580         break;
581       case TypeCodes::f32:
582       {
583         uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
584             data_location, 4, 0, error);
585         if (error.Fail())
586           return false;
587         float flt_value = 0.0f;
588         memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int));
589         NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
590         success = true;
591         break;
592       }
593       case TypeCodes::f64:
594       {
595         uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
596             data_location, 8, 0, error);
597         if (error.Fail())
598           return false;
599         double dbl_value = 0.0;
600         memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng));
601         NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
602         success = true;
603         break;
604       }
605       case TypeCodes::sint128: // internally, this is the same
606       {
607         uint64_t words[2];
608         words[1] = process_sp->ReadUnsignedIntegerFromMemory(
609             data_location, 8, 0, error);
610         if (error.Fail())
611           return false;
612         words[0] = process_sp->ReadUnsignedIntegerFromMemory(
613             data_location + 8, 8, 0, error);
614         if (error.Fail())
615           return false;
616         llvm::APInt i128_value(128, words);
617         NSNumber_FormatInt128(valobj, stream, i128_value, options.GetLanguage());
618         success = true;
619         break;
620       }
621       }
622       return success;
623     }
624   }
625
626   return false;
627 }
628
629 bool lldb_private::formatters::NSURLSummaryProvider(
630     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
631   ProcessSP process_sp = valobj.GetProcessSP();
632   if (!process_sp)
633     return false;
634
635   ObjCLanguageRuntime *runtime =
636       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
637           lldb::eLanguageTypeObjC);
638
639   if (!runtime)
640     return false;
641
642   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
643       runtime->GetClassDescriptor(valobj));
644
645   if (!descriptor || !descriptor->IsValid())
646     return false;
647
648   uint32_t ptr_size = process_sp->GetAddressByteSize();
649
650   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
651
652   if (!valobj_addr)
653     return false;
654
655   llvm::StringRef class_name = descriptor->GetClassName().GetStringRef();
656
657   if (!class_name.equals("NSURL"))
658     return false;
659
660   uint64_t offset_text = ptr_size + ptr_size +
661                          8; // ISA + pointer + 8 bytes of data (even on 32bit)
662   uint64_t offset_base = offset_text + ptr_size;
663   CompilerType type(valobj.GetCompilerType());
664   ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
665   ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
666   if (!text)
667     return false;
668   if (text->GetValueAsUnsigned(0) == 0)
669     return false;
670   StreamString summary;
671   if (!NSStringSummaryProvider(*text, summary, options))
672     return false;
673   if (base && base->GetValueAsUnsigned(0)) {
674     std::string summary_str = summary.GetString();
675
676     if (!summary_str.empty())
677       summary_str.pop_back();
678     summary_str += " -- ";
679     StreamString base_summary;
680     if (NSURLSummaryProvider(*base, base_summary, options) &&
681         !base_summary.Empty()) {
682       llvm::StringRef base_str = base_summary.GetString();
683       if (base_str.size() > 2)
684         base_str = base_str.drop_front(2);
685       summary_str += base_str;
686     }
687     summary.Clear();
688     summary.PutCString(summary_str);
689   }
690   if (!summary.Empty()) {
691     stream.PutCString(summary.GetString());
692     return true;
693   }
694
695   return false;
696 }
697
698 bool lldb_private::formatters::NSDateSummaryProvider(
699     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
700   ProcessSP process_sp = valobj.GetProcessSP();
701   if (!process_sp)
702     return false;
703
704   ObjCLanguageRuntime *runtime =
705       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
706           lldb::eLanguageTypeObjC);
707
708   if (!runtime)
709     return false;
710
711   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
712       runtime->GetClassDescriptor(valobj));
713
714   if (!descriptor || !descriptor->IsValid())
715     return false;
716
717   uint32_t ptr_size = process_sp->GetAddressByteSize();
718
719   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
720
721   if (!valobj_addr)
722     return false;
723
724   uint64_t date_value_bits = 0;
725   double date_value = 0.0;
726
727   ConstString class_name = descriptor->GetClassName();
728
729   static const ConstString g_NSDate("NSDate");
730   static const ConstString g___NSDate("__NSDate");
731   static const ConstString g___NSTaggedDate("__NSTaggedDate");
732   static const ConstString g_NSCalendarDate("NSCalendarDate");
733
734   if (class_name.IsEmpty())
735     return false;
736
737   if ((class_name == g_NSDate) || (class_name == g___NSDate) ||
738       (class_name == g___NSTaggedDate)) {
739     uint64_t info_bits = 0, value_bits = 0;
740     if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits)) {
741       date_value_bits = ((value_bits << 8) | (info_bits << 4));
742       memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
743     } else {
744       llvm::Triple triple(
745           process_sp->GetTarget().GetArchitecture().GetTriple());
746       uint32_t delta =
747           (triple.isWatchOS() && triple.isWatchABI()) ? 8 : ptr_size;
748       Status error;
749       date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
750           valobj_addr + delta, 8, 0, error);
751       memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
752       if (error.Fail())
753         return false;
754     }
755   } else if (class_name == g_NSCalendarDate) {
756     Status error;
757     date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
758         valobj_addr + 2 * ptr_size, 8, 0, error);
759     memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
760     if (error.Fail())
761       return false;
762   } else
763     return false;
764
765   if (date_value == -63114076800) {
766     stream.Printf("0001-12-30 00:00:00 +0000");
767     return true;
768   }
769   // this snippet of code assumes that time_t == seconds since Jan-1-1970
770   // this is generally true and POSIXly happy, but might break if a library
771   // vendor decides to get creative
772   time_t epoch = GetOSXEpoch();
773   epoch = epoch + (time_t)date_value;
774   tm *tm_date = gmtime(&epoch);
775   if (!tm_date)
776     return false;
777   std::string buffer(1024, 0);
778   if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
779     return false;
780   stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
781                 tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
782                 tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
783   return true;
784 }
785
786 bool lldb_private::formatters::ObjCClassSummaryProvider(
787     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
788   ProcessSP process_sp = valobj.GetProcessSP();
789   if (!process_sp)
790     return false;
791
792   ObjCLanguageRuntime *runtime =
793       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
794           lldb::eLanguageTypeObjC);
795
796   if (!runtime)
797     return false;
798
799   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
800       runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
801
802   if (!descriptor || !descriptor->IsValid())
803     return false;
804
805   ConstString class_name = descriptor->GetClassName();
806
807   if (class_name.IsEmpty())
808     return false;
809
810   if (ConstString cs =
811           Mangled(class_name).GetDemangledName(lldb::eLanguageTypeUnknown))
812     class_name = cs;
813
814   stream.Printf("%s", class_name.AsCString("<unknown class>"));
815   return true;
816 }
817
818 class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd {
819 public:
820   ObjCClassSyntheticChildrenFrontEnd(lldb::ValueObjectSP valobj_sp)
821       : SyntheticChildrenFrontEnd(*valobj_sp) {}
822
823   ~ObjCClassSyntheticChildrenFrontEnd() override = default;
824
825   size_t CalculateNumChildren() override { return 0; }
826
827   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
828     return lldb::ValueObjectSP();
829   }
830
831   bool Update() override { return false; }
832
833   bool MightHaveChildren() override { return false; }
834
835   size_t GetIndexOfChildWithName(const ConstString &name) override {
836     return UINT32_MAX;
837   }
838 };
839
840 SyntheticChildrenFrontEnd *
841 lldb_private::formatters::ObjCClassSyntheticFrontEndCreator(
842     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
843   return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
844 }
845
846 template <bool needs_at>
847 bool lldb_private::formatters::NSDataSummaryProvider(
848     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
849   ProcessSP process_sp = valobj.GetProcessSP();
850   if (!process_sp)
851     return false;
852
853   ObjCLanguageRuntime *runtime =
854       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
855           lldb::eLanguageTypeObjC);
856
857   if (!runtime)
858     return false;
859
860   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
861       runtime->GetClassDescriptor(valobj));
862
863   if (!descriptor || !descriptor->IsValid())
864     return false;
865
866   bool is_64bit = (process_sp->GetAddressByteSize() == 8);
867   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
868
869   if (!valobj_addr)
870     return false;
871
872   uint64_t value = 0;
873
874   const char *class_name = descriptor->GetClassName().GetCString();
875
876   if (!class_name || !*class_name)
877     return false;
878
879   if (!strcmp(class_name, "NSConcreteData") ||
880       !strcmp(class_name, "NSConcreteMutableData") ||
881       !strcmp(class_name, "__NSCFData")) {
882     uint32_t offset = (is_64bit ? 16 : 8);
883     Status error;
884     value = process_sp->ReadUnsignedIntegerFromMemory(
885         valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
886     if (error.Fail())
887       return false;
888   } else if (!strcmp(class_name, "_NSInlineData")) {
889     uint32_t offset = (is_64bit ? 8 : 4);
890     Status error;
891     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, 2,
892                                                       0, error);
893     if (error.Fail())
894       return false;
895   } else if (!strcmp(class_name, "_NSZeroData")) {
896     value = 0;
897   } else
898     return false;
899
900   stream.Printf("%s%" PRIu64 " byte%s%s", (needs_at ? "@\"" : ""), value,
901                 (value != 1 ? "s" : ""), (needs_at ? "\"" : ""));
902
903   return true;
904 }
905
906 bool lldb_private::formatters::ObjCBOOLSummaryProvider(
907     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
908   const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();
909
910   ValueObjectSP real_guy_sp = valobj.GetSP();
911
912   if (type_info & eTypeIsPointer) {
913     Status err;
914     real_guy_sp = valobj.Dereference(err);
915     if (err.Fail() || !real_guy_sp)
916       return false;
917   } else if (type_info & eTypeIsReference) {
918     real_guy_sp = valobj.GetChildAtIndex(0, true);
919     if (!real_guy_sp)
920       return false;
921   }
922   uint8_t value = (real_guy_sp->GetValueAsUnsigned(0) & 0xFF);
923   switch (value) {
924   case 0:
925     stream.Printf("NO");
926     break;
927   case 1:
928     stream.Printf("YES");
929     break;
930   default:
931     stream.Printf("%u", value);
932     break;
933   }
934   return true;
935 }
936
937 bool lldb_private::formatters::ObjCBooleanSummaryProvider(
938     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
939   lldb::addr_t valobj_ptr_value =
940       valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
941   if (valobj_ptr_value == LLDB_INVALID_ADDRESS)
942     return false;
943
944   ProcessSP process_sp(valobj.GetProcessSP());
945   if (!process_sp)
946     return false;
947
948   if (AppleObjCRuntime *objc_runtime =
949           (AppleObjCRuntime *)process_sp->GetObjCLanguageRuntime()) {
950     lldb::addr_t cf_true = LLDB_INVALID_ADDRESS,
951                  cf_false = LLDB_INVALID_ADDRESS;
952     objc_runtime->GetValuesForGlobalCFBooleans(cf_true, cf_false);
953     if (valobj_ptr_value == cf_true) {
954       stream.PutCString("YES");
955       return true;
956     }
957     if (valobj_ptr_value == cf_false) {
958       stream.PutCString("NO");
959       return true;
960     }
961   }
962
963   return false;
964 }
965
966 template <bool is_sel_ptr>
967 bool lldb_private::formatters::ObjCSELSummaryProvider(
968     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
969   lldb::ValueObjectSP valobj_sp;
970
971   CompilerType charstar(valobj.GetCompilerType()
972                             .GetBasicTypeFromAST(eBasicTypeChar)
973                             .GetPointerType());
974
975   if (!charstar)
976     return false;
977
978   ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
979
980   if (is_sel_ptr) {
981     lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
982     if (data_address == LLDB_INVALID_ADDRESS)
983       return false;
984     valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address,
985                                                           exe_ctx, charstar);
986   } else {
987     DataExtractor data;
988     Status error;
989     valobj.GetData(data, error);
990     if (error.Fail())
991       return false;
992     valobj_sp =
993         ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
994   }
995
996   if (!valobj_sp)
997     return false;
998
999   stream.Printf("%s", valobj_sp->GetSummaryAsCString());
1000   return true;
1001 }
1002
1003 // POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
1004 // this call gives the POSIX equivalent of the Cocoa epoch
1005 time_t lldb_private::formatters::GetOSXEpoch() {
1006   static time_t epoch = 0;
1007   if (!epoch) {
1008 #ifndef _WIN32
1009     tzset();
1010     tm tm_epoch;
1011     tm_epoch.tm_sec = 0;
1012     tm_epoch.tm_hour = 0;
1013     tm_epoch.tm_min = 0;
1014     tm_epoch.tm_mon = 0;
1015     tm_epoch.tm_mday = 1;
1016     tm_epoch.tm_year = 2001 - 1900;
1017     tm_epoch.tm_isdst = -1;
1018     tm_epoch.tm_gmtoff = 0;
1019     tm_epoch.tm_zone = nullptr;
1020     epoch = timegm(&tm_epoch);
1021 #endif
1022   }
1023   return epoch;
1024 }
1025
1026 template bool lldb_private::formatters::NSDataSummaryProvider<true>(
1027     ValueObject &, Stream &, const TypeSummaryOptions &);
1028
1029 template bool lldb_private::formatters::NSDataSummaryProvider<false>(
1030     ValueObject &, Stream &, const TypeSummaryOptions &);
1031
1032 template bool lldb_private::formatters::ObjCSELSummaryProvider<true>(
1033     ValueObject &, Stream &, const TypeSummaryOptions &);
1034
1035 template bool lldb_private::formatters::ObjCSELSummaryProvider<false>(
1036     ValueObject &, Stream &, const TypeSummaryOptions &);