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