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