1254721Semaste//===-- Cocoa.cpp -------------------------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#include "lldb/lldb-python.h"
11254721Semaste
12254721Semaste#include "lldb/DataFormatters/CXXFormatterFunctions.h"
13254721Semaste
14254721Semaste#include "lldb/Core/DataBufferHeap.h"
15254721Semaste#include "lldb/Core/Error.h"
16254721Semaste#include "lldb/Core/Stream.h"
17254721Semaste#include "lldb/Core/ValueObject.h"
18254721Semaste#include "lldb/Core/ValueObjectConstResult.h"
19254721Semaste#include "lldb/Host/Endian.h"
20254721Semaste#include "lldb/Symbol/ClangASTContext.h"
21254721Semaste#include "lldb/Target/ObjCLanguageRuntime.h"
22254721Semaste#include "lldb/Target/Target.h"
23254721Semaste
24254721Semasteusing namespace lldb;
25254721Semasteusing namespace lldb_private;
26254721Semasteusing namespace lldb_private::formatters;
27254721Semaste
28254721Semastebool
29254721Semastelldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream)
30254721Semaste{
31254721Semaste    ProcessSP process_sp = valobj.GetProcessSP();
32254721Semaste    if (!process_sp)
33254721Semaste        return false;
34254721Semaste
35254721Semaste    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
36254721Semaste
37254721Semaste    if (!runtime)
38254721Semaste        return false;
39254721Semaste
40254721Semaste    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
41254721Semaste
42254721Semaste    if (!descriptor.get() || !descriptor->IsValid())
43254721Semaste        return false;
44254721Semaste
45254721Semaste    uint32_t ptr_size = process_sp->GetAddressByteSize();
46254721Semaste
47254721Semaste    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
48254721Semaste
49254721Semaste    if (!valobj_addr)
50254721Semaste        return false;
51254721Semaste
52254721Semaste    const char* class_name = descriptor->GetClassName().GetCString();
53254721Semaste
54254721Semaste    if (!class_name || !*class_name)
55254721Semaste        return false;
56254721Semaste
57254721Semaste    if (!strcmp(class_name,"NSBundle"))
58254721Semaste    {
59254721Semaste        uint64_t offset = 5 * ptr_size;
60254721Semaste        ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
61254721Semaste
62254721Semaste        StreamString summary_stream;
63254721Semaste        bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
64254721Semaste        if (was_nsstring_ok && summary_stream.GetSize() > 0)
65254721Semaste        {
66254721Semaste            stream.Printf("%s",summary_stream.GetData());
67254721Semaste            return true;
68254721Semaste        }
69254721Semaste    }
70254721Semaste    // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
71254721Semaste    // which is encoded differently and needs to be handled by running code
72254721Semaste    return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream);
73254721Semaste}
74254721Semaste
75254721Semastebool
76254721Semastelldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream)
77254721Semaste{
78254721Semaste    ProcessSP process_sp = valobj.GetProcessSP();
79254721Semaste    if (!process_sp)
80254721Semaste        return false;
81254721Semaste
82254721Semaste    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
83254721Semaste
84254721Semaste    if (!runtime)
85254721Semaste        return false;
86254721Semaste
87254721Semaste    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
88254721Semaste
89254721Semaste    if (!descriptor.get() || !descriptor->IsValid())
90254721Semaste        return false;
91254721Semaste
92254721Semaste    uint32_t ptr_size = process_sp->GetAddressByteSize();
93254721Semaste
94254721Semaste    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
95254721Semaste
96254721Semaste    if (!valobj_addr)
97254721Semaste        return false;
98254721Semaste
99254721Semaste    const char* class_name = descriptor->GetClassName().GetCString();
100254721Semaste
101254721Semaste    if (!class_name || !*class_name)
102254721Semaste        return false;
103254721Semaste
104254721Semaste    if (!strcmp(class_name,"__NSTimeZone"))
105254721Semaste    {
106254721Semaste        uint64_t offset = ptr_size;
107254721Semaste        ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
108254721Semaste        StreamString summary_stream;
109254721Semaste        bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
110254721Semaste        if (was_nsstring_ok && summary_stream.GetSize() > 0)
111254721Semaste        {
112254721Semaste            stream.Printf("%s",summary_stream.GetData());
113254721Semaste            return true;
114254721Semaste        }
115254721Semaste    }
116254721Semaste    return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
117254721Semaste}
118254721Semaste
119254721Semastebool
120254721Semastelldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream)
121254721Semaste{
122254721Semaste    ProcessSP process_sp = valobj.GetProcessSP();
123254721Semaste    if (!process_sp)
124254721Semaste        return false;
125254721Semaste
126254721Semaste    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
127254721Semaste
128254721Semaste    if (!runtime)
129254721Semaste        return false;
130254721Semaste
131254721Semaste    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
132254721Semaste
133254721Semaste    if (!descriptor.get() || !descriptor->IsValid())
134254721Semaste        return false;
135254721Semaste
136254721Semaste    uint32_t ptr_size = process_sp->GetAddressByteSize();
137254721Semaste
138254721Semaste    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
139254721Semaste
140254721Semaste    if (!valobj_addr)
141254721Semaste        return false;
142254721Semaste
143254721Semaste    const char* class_name = descriptor->GetClassName().GetCString();
144254721Semaste
145254721Semaste    if (!class_name || !*class_name)
146254721Semaste        return false;
147254721Semaste
148254721Semaste    if (!strcmp(class_name,"NSConcreteNotification"))
149254721Semaste    {
150254721Semaste        uint64_t offset = ptr_size;
151254721Semaste        ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true));
152254721Semaste        StreamString summary_stream;
153254721Semaste        bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
154254721Semaste        if (was_nsstring_ok && summary_stream.GetSize() > 0)
155254721Semaste        {
156254721Semaste            stream.Printf("%s",summary_stream.GetData());
157254721Semaste            return true;
158254721Semaste        }
159254721Semaste    }
160254721Semaste    // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
161254721Semaste    // which is encoded differently and needs to be handled by running code
162254721Semaste    return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
163254721Semaste}
164254721Semaste
165254721Semastebool
166254721Semastelldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream)
167254721Semaste{
168254721Semaste    ProcessSP process_sp = valobj.GetProcessSP();
169254721Semaste    if (!process_sp)
170254721Semaste        return false;
171254721Semaste
172254721Semaste    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
173254721Semaste
174254721Semaste    if (!runtime)
175254721Semaste        return false;
176254721Semaste
177254721Semaste    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
178254721Semaste
179254721Semaste    if (!descriptor.get() || !descriptor->IsValid())
180254721Semaste        return false;
181254721Semaste
182254721Semaste    uint32_t ptr_size = process_sp->GetAddressByteSize();
183254721Semaste
184254721Semaste    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
185254721Semaste
186254721Semaste    if (!valobj_addr)
187254721Semaste        return false;
188254721Semaste
189254721Semaste    const char* class_name = descriptor->GetClassName().GetCString();
190254721Semaste
191254721Semaste    if (!class_name || !*class_name)
192254721Semaste        return false;
193254721Semaste
194254721Semaste    uint64_t port_number = 0;
195254721Semaste
196254721Semaste    do
197254721Semaste    {
198254721Semaste        if (!strcmp(class_name,"NSMachPort"))
199254721Semaste        {
200254721Semaste            uint64_t offset = (ptr_size == 4 ? 12 : 20);
201254721Semaste            Error error;
202254721Semaste            port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error);
203254721Semaste            if (error.Success())
204254721Semaste                break;
205254721Semaste        }
206254721Semaste        if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number))
207254721Semaste            return false;
208254721Semaste    } while (false);
209254721Semaste
210254721Semaste    stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF));
211254721Semaste    return true;
212254721Semaste}
213254721Semaste
214254721Semastebool
215254721Semastelldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream)
216254721Semaste{
217254721Semaste    ProcessSP process_sp = valobj.GetProcessSP();
218254721Semaste    if (!process_sp)
219254721Semaste        return false;
220254721Semaste
221254721Semaste    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
222254721Semaste
223254721Semaste    if (!runtime)
224254721Semaste        return false;
225254721Semaste
226254721Semaste    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
227254721Semaste
228254721Semaste    if (!descriptor.get() || !descriptor->IsValid())
229254721Semaste        return false;
230254721Semaste
231254721Semaste    uint32_t ptr_size = process_sp->GetAddressByteSize();
232254721Semaste
233254721Semaste    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
234254721Semaste
235254721Semaste    if (!valobj_addr)
236254721Semaste        return false;
237254721Semaste
238254721Semaste    const char* class_name = descriptor->GetClassName().GetCString();
239254721Semaste
240254721Semaste    if (!class_name || !*class_name)
241254721Semaste        return false;
242254721Semaste
243254721Semaste    uint64_t count = 0;
244254721Semaste
245254721Semaste    do {
246254721Semaste        if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet"))
247254721Semaste        {
248254721Semaste            Error error;
249254721Semaste            uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error);
250254721Semaste            if (error.Fail())
251254721Semaste                return false;
252254721Semaste            // this means the set is empty - count = 0
253254721Semaste            if ((mode & 1) == 1)
254254721Semaste            {
255254721Semaste                count = 0;
256254721Semaste                break;
257254721Semaste            }
258254721Semaste            if ((mode & 2) == 2)
259254721Semaste                mode = 1; // this means the set only has one range
260254721Semaste            else
261254721Semaste                mode = 2; // this means the set has multiple ranges
262254721Semaste            if (mode == 1)
263254721Semaste            {
264254721Semaste                count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error);
265254721Semaste                if (error.Fail())
266254721Semaste                    return false;
267254721Semaste            }
268254721Semaste            else
269254721Semaste            {
270254721Semaste                // read a pointer to the data at 2*ptr_size
271254721Semaste                count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
272254721Semaste                if (error.Fail())
273254721Semaste                    return false;
274254721Semaste                // read the data at 2*ptr_size from the first location
275254721Semaste                count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error);
276254721Semaste                if (error.Fail())
277254721Semaste                    return false;
278254721Semaste            }
279254721Semaste        }
280254721Semaste        else
281254721Semaste        {
282254721Semaste            if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count))
283254721Semaste                return false;
284254721Semaste        }
285254721Semaste    }  while (false);
286254721Semaste    stream.Printf("%" PRIu64 " index%s",
287254721Semaste                  count,
288254721Semaste                  (count == 1 ? "" : "es"));
289254721Semaste    return true;
290254721Semaste}
291254721Semaste
292254721Semastebool
293254721Semastelldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream)
294254721Semaste{
295254721Semaste    ProcessSP process_sp = valobj.GetProcessSP();
296254721Semaste    if (!process_sp)
297254721Semaste        return false;
298254721Semaste
299254721Semaste    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
300254721Semaste
301254721Semaste    if (!runtime)
302254721Semaste        return false;
303254721Semaste
304254721Semaste    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
305254721Semaste
306254721Semaste    if (!descriptor.get() || !descriptor->IsValid())
307254721Semaste        return false;
308254721Semaste
309254721Semaste    uint32_t ptr_size = process_sp->GetAddressByteSize();
310254721Semaste
311254721Semaste    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
312254721Semaste
313254721Semaste    if (!valobj_addr)
314254721Semaste        return false;
315254721Semaste
316254721Semaste    const char* class_name = descriptor->GetClassName().GetCString();
317254721Semaste
318254721Semaste    if (!class_name || !*class_name)
319254721Semaste        return false;
320254721Semaste
321254721Semaste    if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
322254721Semaste    {
323254721Semaste        uint64_t value = 0;
324254721Semaste        uint64_t i_bits = 0;
325254721Semaste        if (descriptor->GetTaggedPointerInfo(&i_bits,&value))
326254721Semaste        {
327254721Semaste            switch (i_bits)
328254721Semaste            {
329254721Semaste                case 0:
330254721Semaste                    stream.Printf("(char)%hhd",(char)value);
331254721Semaste                    break;
332254721Semaste                case 1:
333254721Semaste                case 4:
334254721Semaste                    stream.Printf("(short)%hd",(short)value);
335254721Semaste                    break;
336254721Semaste                case 2:
337254721Semaste                case 8:
338254721Semaste                    stream.Printf("(int)%d",(int)value);
339254721Semaste                    break;
340254721Semaste                case 3:
341254721Semaste                case 12:
342254721Semaste                    stream.Printf("(long)%" PRId64,value);
343254721Semaste                    break;
344254721Semaste                default:
345254721Semaste                    stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value);
346254721Semaste                    break;
347254721Semaste            }
348254721Semaste            return true;
349254721Semaste        }
350254721Semaste        else
351254721Semaste        {
352254721Semaste            Error error;
353254721Semaste            uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
354254721Semaste            uint64_t data_location = valobj_addr + 2*ptr_size;
355254721Semaste            uint64_t value = 0;
356254721Semaste            if (error.Fail())
357254721Semaste                return false;
358254721Semaste            switch (data_type)
359254721Semaste            {
360254721Semaste                case 1: // 0B00001
361254721Semaste                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
362254721Semaste                    if (error.Fail())
363254721Semaste                        return false;
364254721Semaste                    stream.Printf("(char)%hhd",(char)value);
365254721Semaste                    break;
366254721Semaste                case 2: // 0B0010
367254721Semaste                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
368254721Semaste                    if (error.Fail())
369254721Semaste                        return false;
370254721Semaste                    stream.Printf("(short)%hd",(short)value);
371254721Semaste                    break;
372254721Semaste                case 3: // 0B0011
373254721Semaste                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
374254721Semaste                    if (error.Fail())
375254721Semaste                        return false;
376254721Semaste                    stream.Printf("(int)%d",(int)value);
377254721Semaste                    break;
378254721Semaste                case 17: // 0B10001
379254721Semaste                    data_location += 8;
380254721Semaste                case 4: // 0B0100
381254721Semaste                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
382254721Semaste                    if (error.Fail())
383254721Semaste                        return false;
384254721Semaste                    stream.Printf("(long)%" PRId64,value);
385254721Semaste                    break;
386254721Semaste                case 5: // 0B0101
387254721Semaste                {
388254721Semaste                    uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
389254721Semaste                    if (error.Fail())
390254721Semaste                        return false;
391254721Semaste                    float flt_value = *((float*)&flt_as_int);
392254721Semaste                    stream.Printf("(float)%f",flt_value);
393254721Semaste                    break;
394254721Semaste                }
395254721Semaste                case 6: // 0B0110
396254721Semaste                {
397254721Semaste                    uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
398254721Semaste                    if (error.Fail())
399254721Semaste                        return false;
400254721Semaste                    double dbl_value = *((double*)&dbl_as_lng);
401254721Semaste                    stream.Printf("(double)%g",dbl_value);
402254721Semaste                    break;
403254721Semaste                }
404254721Semaste                default:
405254721Semaste                    stream.Printf("unexpected value: dt=%d",data_type);
406254721Semaste                    break;
407254721Semaste            }
408254721Semaste            return true;
409254721Semaste        }
410254721Semaste    }
411254721Semaste    else
412254721Semaste    {
413254721Semaste        return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
414254721Semaste    }
415254721Semaste}
416254721Semaste
417254721Semastebool
418254721Semastelldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream)
419254721Semaste{
420254721Semaste    ProcessSP process_sp = valobj.GetProcessSP();
421254721Semaste    if (!process_sp)
422254721Semaste        return false;
423254721Semaste
424254721Semaste    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
425254721Semaste
426254721Semaste    if (!runtime)
427254721Semaste        return false;
428254721Semaste
429254721Semaste    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
430254721Semaste
431254721Semaste    if (!descriptor.get() || !descriptor->IsValid())
432254721Semaste        return false;
433254721Semaste
434254721Semaste    uint32_t ptr_size = process_sp->GetAddressByteSize();
435254721Semaste
436254721Semaste    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
437254721Semaste
438254721Semaste    if (!valobj_addr)
439254721Semaste        return false;
440254721Semaste
441254721Semaste    const char* class_name = descriptor->GetClassName().GetCString();
442254721Semaste
443254721Semaste    if (!class_name || !*class_name)
444254721Semaste        return false;
445254721Semaste
446254721Semaste    if (strcmp(class_name, "NSURL") == 0)
447254721Semaste    {
448254721Semaste        uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit)
449254721Semaste        uint64_t offset_base = offset_text + ptr_size;
450254721Semaste        ClangASTType type(valobj.GetClangType());
451254721Semaste        ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
452254721Semaste        ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
453254721Semaste        if (!text)
454254721Semaste            return false;
455254721Semaste        if (text->GetValueAsUnsigned(0) == 0)
456254721Semaste            return false;
457254721Semaste        StreamString summary;
458254721Semaste        if (!NSStringSummaryProvider(*text, summary))
459254721Semaste            return false;
460254721Semaste        if (base && base->GetValueAsUnsigned(0))
461254721Semaste        {
462254721Semaste            if (summary.GetSize() > 0)
463254721Semaste                summary.GetString().resize(summary.GetSize()-1);
464254721Semaste            summary.Printf(" -- ");
465254721Semaste            StreamString base_summary;
466254721Semaste            if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0)
467254721Semaste                summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
468254721Semaste        }
469254721Semaste        if (summary.GetSize())
470254721Semaste        {
471254721Semaste            stream.Printf("%s",summary.GetData());
472254721Semaste            return true;
473254721Semaste        }
474254721Semaste    }
475254721Semaste    else
476254721Semaste    {
477254721Semaste        return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream);
478254721Semaste    }
479254721Semaste    return false;
480254721Semaste}
481254721Semaste
482254721Semastebool
483254721Semastelldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream)
484254721Semaste{
485254721Semaste    ProcessSP process_sp = valobj.GetProcessSP();
486254721Semaste    if (!process_sp)
487254721Semaste        return false;
488254721Semaste
489254721Semaste    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
490254721Semaste
491254721Semaste    if (!runtime)
492254721Semaste        return false;
493254721Semaste
494254721Semaste    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
495254721Semaste
496254721Semaste    if (!descriptor.get() || !descriptor->IsValid())
497254721Semaste        return false;
498254721Semaste
499254721Semaste    uint32_t ptr_size = process_sp->GetAddressByteSize();
500254721Semaste
501254721Semaste    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
502254721Semaste
503254721Semaste    if (!valobj_addr)
504254721Semaste        return false;
505254721Semaste
506254721Semaste    uint64_t date_value_bits = 0;
507254721Semaste    double date_value = 0.0;
508254721Semaste
509254721Semaste    const char* class_name = descriptor->GetClassName().GetCString();
510254721Semaste
511254721Semaste    if (!class_name || !*class_name)
512254721Semaste        return false;
513254721Semaste
514254721Semaste    if (strcmp(class_name,"NSDate") == 0 ||
515254721Semaste        strcmp(class_name,"__NSDate") == 0 ||
516254721Semaste        strcmp(class_name,"__NSTaggedDate") == 0)
517254721Semaste    {
518254721Semaste        uint64_t info_bits=0,value_bits = 0;
519254721Semaste        if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
520254721Semaste        {
521254721Semaste            date_value_bits = ((value_bits << 8) | (info_bits << 4));
522254721Semaste            date_value = *((double*)&date_value_bits);
523254721Semaste        }
524254721Semaste        else
525254721Semaste        {
526254721Semaste            Error error;
527254721Semaste            date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
528254721Semaste            date_value = *((double*)&date_value_bits);
529254721Semaste            if (error.Fail())
530254721Semaste                return false;
531254721Semaste        }
532254721Semaste    }
533254721Semaste    else if (!strcmp(class_name,"NSCalendarDate"))
534254721Semaste    {
535254721Semaste        Error error;
536254721Semaste        date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
537254721Semaste        date_value = *((double*)&date_value_bits);
538254721Semaste        if (error.Fail())
539254721Semaste            return false;
540254721Semaste    }
541254721Semaste    else
542254721Semaste    {
543254721Semaste        if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
544254721Semaste            return false;
545254721Semaste        date_value = *((double*)&date_value_bits);
546254721Semaste    }
547254721Semaste    if (date_value == -63114076800)
548254721Semaste    {
549254721Semaste        stream.Printf("0001-12-30 00:00:00 +0000");
550254721Semaste        return true;
551254721Semaste    }
552254721Semaste    // this snippet of code assumes that time_t == seconds since Jan-1-1970
553254721Semaste    // this is generally true and POSIXly happy, but might break if a library
554254721Semaste    // vendor decides to get creative
555254721Semaste    time_t epoch = GetOSXEpoch();
556254721Semaste    epoch = epoch + (time_t)date_value;
557254721Semaste    tm *tm_date = localtime(&epoch);
558254721Semaste    if (!tm_date)
559254721Semaste        return false;
560254721Semaste    std::string buffer(1024,0);
561254721Semaste    if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
562254721Semaste        return false;
563254721Semaste    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());
564254721Semaste    return true;
565254721Semaste}
566