CXXFormatterFunctions.cpp revision cba09f60618744e2155bc97c9049fa9c797698ad
1//===-- CXXFormatterFunctions.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 "lldb/lldb-python.h"
11
12#include <time.h>
13
14#include "lldb/DataFormatters/CXXFormatterFunctions.h"
15
16#include "llvm/Support/ConvertUTF.h"
17
18#include "lldb/Core/DataBufferHeap.h"
19#include "lldb/Core/Error.h"
20#include "lldb/Core/Stream.h"
21#include "lldb/Core/ValueObject.h"
22#include "lldb/Core/ValueObjectConstResult.h"
23#include "lldb/Host/Endian.h"
24#include "lldb/Symbol/ClangASTContext.h"
25#include "lldb/Target/ObjCLanguageRuntime.h"
26#include "lldb/Target/Target.h"
27
28using namespace lldb;
29using namespace lldb_private;
30using namespace lldb_private::formatters;
31
32bool
33lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
34                                                          const char* target_type,
35                                                          const char* selector,
36                                                          uint64_t &value)
37{
38    if (!target_type || !*target_type)
39        return false;
40    if (!selector || !*selector)
41        return false;
42    StreamString expr;
43    expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
44    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
45    lldb::ValueObjectSP result_sp;
46    Target* target = exe_ctx.GetTargetPtr();
47    StackFrame* stack_frame = exe_ctx.GetFramePtr();
48    if (!target || !stack_frame)
49        return false;
50
51    EvaluateExpressionOptions options;
52    options.SetCoerceToId(false)
53    .SetUnwindOnError(true)
54    .SetKeepInMemory(true);
55
56    target->EvaluateExpression(expr.GetData(),
57                               stack_frame,
58                               result_sp,
59                               options);
60    if (!result_sp)
61        return false;
62    value = result_sp->GetValueAsUnsigned(0);
63    return true;
64}
65
66bool
67lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj,
68                                                            const char* target_type,
69                                                            const char* selector,
70                                                            Stream &stream)
71{
72    if (!target_type || !*target_type)
73        return false;
74    if (!selector || !*selector)
75        return false;
76    StreamString expr;
77    expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
78    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
79    lldb::ValueObjectSP result_sp;
80    Target* target = exe_ctx.GetTargetPtr();
81    StackFrame* stack_frame = exe_ctx.GetFramePtr();
82    if (!target || !stack_frame)
83        return false;
84
85    EvaluateExpressionOptions options;
86    options.SetCoerceToId(false)
87    .SetUnwindOnError(true)
88    .SetKeepInMemory(true)
89    .SetUseDynamic(lldb::eDynamicCanRunTarget);
90
91    target->EvaluateExpression(expr.GetData(),
92                               stack_frame,
93                               result_sp,
94                               options);
95    if (!result_sp)
96        return false;
97    stream.Printf("%s",result_sp->GetSummaryAsCString());
98    return true;
99}
100
101lldb::ValueObjectSP
102lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
103                                                const char* return_type,
104                                                const char* selector,
105                                                uint64_t index)
106{
107    lldb::ValueObjectSP valobj_sp;
108    if (!return_type || !*return_type)
109        return valobj_sp;
110    if (!selector || !*selector)
111        return valobj_sp;
112    StreamString expr_path_stream;
113    valobj.GetExpressionPath(expr_path_stream, false);
114    StreamString expr;
115    expr.Printf("(%s)[%s %s:%" PRId64 "]",return_type,expr_path_stream.GetData(),selector,index);
116    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
117    lldb::ValueObjectSP result_sp;
118    Target* target = exe_ctx.GetTargetPtr();
119    StackFrame* stack_frame = exe_ctx.GetFramePtr();
120    if (!target || !stack_frame)
121        return valobj_sp;
122
123    EvaluateExpressionOptions options;
124    options.SetCoerceToId(false)
125    .SetUnwindOnError(true)
126    .SetKeepInMemory(true)
127    .SetUseDynamic(lldb::eDynamicCanRunTarget);
128
129    target->EvaluateExpression(expr.GetData(),
130                               stack_frame,
131                               valobj_sp,
132                               options);
133    return valobj_sp;
134}
135
136lldb::ValueObjectSP
137lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
138                                                const char* return_type,
139                                                const char* selector,
140                                                const char* key)
141{
142    lldb::ValueObjectSP valobj_sp;
143    if (!return_type || !*return_type)
144        return valobj_sp;
145    if (!selector || !*selector)
146        return valobj_sp;
147    if (!key || !*key)
148        return valobj_sp;
149    StreamString expr_path_stream;
150    valobj.GetExpressionPath(expr_path_stream, false);
151    StreamString expr;
152    expr.Printf("(%s)[%s %s:%s]",return_type,expr_path_stream.GetData(),selector,key);
153    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
154    lldb::ValueObjectSP result_sp;
155    Target* target = exe_ctx.GetTargetPtr();
156    StackFrame* stack_frame = exe_ctx.GetFramePtr();
157    if (!target || !stack_frame)
158        return valobj_sp;
159
160    EvaluateExpressionOptions options;
161    options.SetCoerceToId(false)
162    .SetUnwindOnError(true)
163    .SetKeepInMemory(true)
164    .SetUseDynamic(lldb::eDynamicCanRunTarget);
165
166    target->EvaluateExpression(expr.GetData(),
167                               stack_frame,
168                               valobj_sp,
169                               options);
170    return valobj_sp;
171}
172
173// use this call if you already have an LLDB-side buffer for the data
174template<typename SourceDataType>
175static bool
176DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
177                                                            const SourceDataType*,
178                                                            UTF8**,
179                                                            UTF8*,
180                                                            ConversionFlags),
181                       DataExtractor& data,
182                       Stream& stream,
183                       char prefix_token = '@',
184                       char quote = '"',
185                       int sourceSize = 0)
186{
187    if (prefix_token != 0)
188        stream.Printf("%c",prefix_token);
189    if (quote != 0)
190        stream.Printf("%c",quote);
191    if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
192    {
193        const int bufferSPSize = data.GetByteSize();
194        if (sourceSize == 0)
195        {
196            const int origin_encoding = 8*sizeof(SourceDataType);
197            sourceSize = bufferSPSize/(origin_encoding / 4);
198        }
199
200        SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart();
201        SourceDataType *data_end_ptr = data_ptr + sourceSize;
202
203        while (data_ptr < data_end_ptr)
204        {
205            if (!*data_ptr)
206            {
207                data_end_ptr = data_ptr;
208                break;
209            }
210            data_ptr++;
211        }
212
213        data_ptr = (SourceDataType*)data.GetDataStart();
214
215        lldb::DataBufferSP utf8_data_buffer_sp;
216        UTF8* utf8_data_ptr = nullptr;
217        UTF8* utf8_data_end_ptr = nullptr;
218
219        if (ConvertFunction)
220        {
221            utf8_data_buffer_sp.reset(new DataBufferHeap(bufferSPSize,0));
222            utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
223            utf8_data_end_ptr = utf8_data_ptr + bufferSPSize;
224            ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
225            utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
226        }
227        else
228        {
229            // just copy the pointers - the cast is necessary to make the compiler happy
230            // but this should only happen if we are reading UTF8 data
231            utf8_data_ptr = (UTF8*)data_ptr;
232            utf8_data_end_ptr = (UTF8*)data_end_ptr;
233        }
234
235        // since we tend to accept partial data (and even partially malformed data)
236        // we might end up with no NULL terminator before the end_ptr
237        // hence we need to take a slower route and ensure we stay within boundaries
238        for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++)
239        {
240            if (!*utf8_data_ptr)
241                break;
242            stream.Printf("%c",*utf8_data_ptr);
243        }
244    }
245    if (quote != 0)
246        stream.Printf("%c",quote);
247    return true;
248}
249
250template<typename SourceDataType>
251static bool
252ReadUTFBufferAndDumpToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
253                                                                   const SourceDataType*,
254                                                                   UTF8**,
255                                                                   UTF8*,
256                                                                   ConversionFlags),
257                              uint64_t location,
258                              const ProcessSP& process_sp,
259                              Stream& stream,
260                              char prefix_token = '@',
261                              char quote = '"',
262                              int sourceSize = 0)
263{
264    if (location == 0 || location == LLDB_INVALID_ADDRESS)
265        return false;
266    if (!process_sp)
267        return false;
268
269    const int origin_encoding = 8*sizeof(SourceDataType);
270    if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
271        return false;
272    // if not UTF8, I need a conversion function to return proper UTF8
273    if (origin_encoding != 8 && !ConvertFunction)
274        return false;
275
276    if (sourceSize == 0)
277        sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
278    const int bufferSPSize = sourceSize * (origin_encoding >> 2);
279
280    Error error;
281    lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
282
283    if (!buffer_sp->GetBytes())
284        return false;
285
286    size_t data_read = process_sp->ReadMemoryFromInferior(location, (char*)buffer_sp->GetBytes(), bufferSPSize, error);
287    if (error.Fail() || data_read == 0)
288    {
289        stream.Printf("unable to read data");
290        return true;
291    }
292
293    DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
294
295    return DumpUTFBufferToStream(ConvertFunction, data, stream, prefix_token, quote, sourceSize);
296}
297
298bool
299lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream)
300{
301    ProcessSP process_sp = valobj.GetProcessSP();
302    if (!process_sp)
303        return false;
304
305    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
306
307    if (!valobj_addr)
308        return false;
309
310    if (!ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8,valobj_addr,
311                                                                 process_sp,
312                                                                 stream,
313                                                                 'u'))
314    {
315        stream.Printf("Summary Unavailable");
316        return true;
317    }
318
319    return true;
320}
321
322bool
323lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream)
324{
325    ProcessSP process_sp = valobj.GetProcessSP();
326    if (!process_sp)
327        return false;
328
329    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
330
331    if (!valobj_addr)
332        return false;
333
334    if (!ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8,valobj_addr,
335                                                                 process_sp,
336                                                                 stream,
337                                                                 'U'))
338    {
339        stream.Printf("Summary Unavailable");
340        return true;
341    }
342
343    return true;
344}
345
346bool
347lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream)
348{
349    ProcessSP process_sp = valobj.GetProcessSP();
350    if (!process_sp)
351        return false;
352
353    lldb::addr_t data_addr = 0;
354
355    if (valobj.IsPointerType())
356        data_addr = valobj.GetValueAsUnsigned(0);
357    else if (valobj.IsArrayType())
358        data_addr = valobj.GetAddressOf();
359
360    if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS)
361        return false;
362
363    clang::ASTContext* ast = valobj.GetClangAST();
364
365    if (!ast)
366        return false;
367
368    uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
369
370    switch (wchar_size)
371    {
372        case 8:
373            // utf 8
374            return ReadUTFBufferAndDumpToStream<UTF8>(nullptr, data_addr,
375                                                               process_sp,
376                                                               stream,
377                                                               'L');
378        case 16:
379            // utf 16
380            return ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8, data_addr,
381                                                                           process_sp,
382                                                                           stream,
383                                                                           'L');
384        case 32:
385            // utf 32
386            return ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8, data_addr,
387                                                                           process_sp,
388                                                                           stream,
389                                                                           'L');
390        default:
391            stream.Printf("size for wchar_t is not valid");
392            return true;
393    }
394    return true;
395}
396
397bool
398lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
399{
400    DataExtractor data;
401    valobj.GetData(data);
402
403    std::string value;
404    valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
405    if (!value.empty())
406        stream.Printf("%s ", value.c_str());
407
408    return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1);
409}
410
411bool
412lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
413{
414    DataExtractor data;
415    valobj.GetData(data);
416
417    std::string value;
418    valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
419    if (!value.empty())
420        stream.Printf("%s ", value.c_str());
421
422    return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1);
423}
424
425bool
426lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
427{
428    DataExtractor data;
429    valobj.GetData(data);
430
431    clang::ASTContext* ast = valobj.GetClangAST();
432
433    if (!ast)
434        return false;
435
436    std::string value;
437
438    uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
439
440    switch (wchar_size)
441    {
442        case 8:
443            // utf 8
444            valobj.GetValueAsCString(lldb::eFormatChar, value);
445            if (!value.empty())
446                stream.Printf("%s ", value.c_str());
447            return DumpUTFBufferToStream<UTF8>(nullptr,
448                                               data,
449                                               stream,
450                                               'L',
451                                               '\'',
452                                               1);
453        case 16:
454            // utf 16
455            valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
456            if (!value.empty())
457                stream.Printf("%s ", value.c_str());
458            return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,
459                                                data,
460                                                stream,
461                                                'L',
462                                                '\'',
463                                                1);
464        case 32:
465            // utf 32
466            valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
467            if (!value.empty())
468                stream.Printf("%s ", value.c_str());
469            return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,
470                                                data,
471                                                stream,
472                                                'L',
473                                                '\'',
474                                                1);
475        default:
476            stream.Printf("size for wchar_t is not valid");
477            return true;
478    }
479    return true;
480}
481
482// this function extracts information from a libcxx std::basic_string<>
483// irregardless of template arguments. it reports the size (in item count not bytes)
484// and the location in memory where the string data can be found
485static bool
486ExtractLibcxxStringInfo (ValueObject& valobj,
487                         ValueObjectSP &location_sp,
488                         uint64_t& size)
489{
490    ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
491    if (!D)
492        return false;
493
494    ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
495    if (!size_mode)
496        return false;
497
498    uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0));
499
500    if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline
501    {
502        ValueObjectSP s(D->GetChildAtIndex(1, true));
503        if (!s)
504            return false;
505        size = ((size_mode_value >> 1) % 256);
506        location_sp = s->GetChildAtIndex(1, true);
507        return (location_sp.get() != nullptr);
508    }
509    else
510    {
511        ValueObjectSP l(D->GetChildAtIndex(0, true));
512        if (!l)
513            return false;
514        location_sp = l->GetChildAtIndex(2, true);
515        ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
516        if (!size_vo || !location_sp)
517            return false;
518        size = size_vo->GetValueAsUnsigned(0);
519        return true;
520    }
521}
522
523bool
524lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
525{
526    uint64_t size = 0;
527    ValueObjectSP location_sp((ValueObject*)nullptr);
528    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
529        return false;
530    if (size == 0)
531    {
532        stream.Printf("L\"\"");
533        return true;
534    }
535    if (!location_sp)
536        return false;
537    return WCharStringSummaryProvider(*location_sp.get(), stream);
538}
539
540bool
541lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
542{
543    uint64_t size = 0;
544    ValueObjectSP location_sp((ValueObject*)nullptr);
545    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
546        return false;
547    if (size == 0)
548    {
549        stream.Printf("\"\"");
550        return true;
551    }
552    if (!location_sp)
553        return false;
554    Error error;
555    if (location_sp->ReadPointedString(stream,
556                                       error,
557                                       0, // max length is decided by the settings
558                                       false) == 0) // do not honor array (terminates on first 0 byte even for a char[])
559        stream.Printf("\"\""); // if nothing was read, print an empty string
560    return error.Success();
561}
562
563bool
564lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream)
565{
566    ProcessSP process_sp = valobj.GetProcessSP();
567    if (!process_sp)
568        return false;
569
570    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
571
572    if (!runtime)
573        return false;
574
575    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj.GetValueAsUnsigned(0)));
576
577    if (!descriptor.get() || !descriptor->IsValid())
578        return false;
579
580    const char* class_name = descriptor->GetClassName().GetCString();
581
582    if (!class_name || !*class_name)
583        return false;
584
585    stream.Printf("%s",class_name);
586    return true;
587}
588
589template<bool needs_at>
590bool
591lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream)
592{
593    ProcessSP process_sp = valobj.GetProcessSP();
594    if (!process_sp)
595        return false;
596
597    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
598
599    if (!runtime)
600        return false;
601
602    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
603
604    if (!descriptor.get() || !descriptor->IsValid())
605        return false;
606
607    bool is_64bit = (process_sp->GetAddressByteSize() == 8);
608    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
609
610    if (!valobj_addr)
611        return false;
612
613    uint64_t value = 0;
614
615    const char* class_name = descriptor->GetClassName().GetCString();
616
617    if (!class_name || !*class_name)
618        return false;
619
620    if (!strcmp(class_name,"NSConcreteData") ||
621        !strcmp(class_name,"NSConcreteMutableData") ||
622        !strcmp(class_name,"__NSCFData"))
623    {
624        uint32_t offset = (is_64bit ? 16 : 8);
625        Error error;
626        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
627        if (error.Fail())
628            return false;
629    }
630    else
631    {
632        if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
633            return false;
634    }
635
636    stream.Printf("%s%" PRIu64 " byte%s%s",
637                  (needs_at ? "@\"" : ""),
638                  value,
639                  (value > 1 ? "s" : ""),
640                  (needs_at ? "\"" : ""));
641
642    return true;
643}
644
645bool
646lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream)
647{
648    ProcessSP process_sp = valobj.GetProcessSP();
649    if (!process_sp)
650        return false;
651
652    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
653
654    if (!runtime)
655        return false;
656
657    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
658
659    if (!descriptor.get() || !descriptor->IsValid())
660        return false;
661
662    uint32_t ptr_size = process_sp->GetAddressByteSize();
663
664    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
665
666    if (!valobj_addr)
667        return false;
668
669    const char* class_name = descriptor->GetClassName().GetCString();
670
671    if (!class_name || !*class_name)
672        return false;
673
674    if (!strcmp(class_name,"NSBundle"))
675    {
676        uint64_t offset = 5 * ptr_size;
677        ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
678        ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true));
679        StreamString summary_stream;
680        bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
681        if (was_nsstring_ok && summary_stream.GetSize() > 0)
682        {
683            stream.Printf("%s",summary_stream.GetData());
684            return true;
685        }
686    }
687    // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
688    // which is encoded differently and needs to be handled by running code
689    return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream);
690}
691
692bool
693lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream)
694{
695    ProcessSP process_sp = valobj.GetProcessSP();
696    if (!process_sp)
697        return false;
698
699    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
700
701    if (!runtime)
702        return false;
703
704    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
705
706    if (!descriptor.get() || !descriptor->IsValid())
707        return false;
708
709    uint32_t ptr_size = process_sp->GetAddressByteSize();
710
711    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
712
713    if (!valobj_addr)
714        return false;
715
716    const char* class_name = descriptor->GetClassName().GetCString();
717
718    if (!class_name || !*class_name)
719        return false;
720
721    if (!strcmp(class_name,"__NSTimeZone"))
722    {
723        uint64_t offset = ptr_size;
724        ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
725        ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true));
726        StreamString summary_stream;
727        bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
728        if (was_nsstring_ok && summary_stream.GetSize() > 0)
729        {
730            stream.Printf("%s",summary_stream.GetData());
731            return true;
732        }
733    }
734    return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
735}
736
737bool
738lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream)
739{
740    ProcessSP process_sp = valobj.GetProcessSP();
741    if (!process_sp)
742        return false;
743
744    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
745
746    if (!runtime)
747        return false;
748
749    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
750
751    if (!descriptor.get() || !descriptor->IsValid())
752        return false;
753
754    uint32_t ptr_size = process_sp->GetAddressByteSize();
755
756    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
757
758    if (!valobj_addr)
759        return false;
760
761    const char* class_name = descriptor->GetClassName().GetCString();
762
763    if (!class_name || !*class_name)
764        return false;
765
766    if (!strcmp(class_name,"NSConcreteNotification"))
767    {
768        uint64_t offset = ptr_size;
769        ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
770        ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true));
771        StreamString summary_stream;
772        bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
773        if (was_nsstring_ok && summary_stream.GetSize() > 0)
774        {
775            stream.Printf("%s",summary_stream.GetData());
776            return true;
777        }
778    }
779    // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
780    // which is encoded differently and needs to be handled by running code
781    return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
782}
783
784bool
785lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream)
786{
787    ProcessSP process_sp = valobj.GetProcessSP();
788    if (!process_sp)
789        return false;
790
791    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
792
793    if (!runtime)
794        return false;
795
796    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
797
798    if (!descriptor.get() || !descriptor->IsValid())
799        return false;
800
801    uint32_t ptr_size = process_sp->GetAddressByteSize();
802
803    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
804
805    if (!valobj_addr)
806        return false;
807
808    const char* class_name = descriptor->GetClassName().GetCString();
809
810    if (!class_name || !*class_name)
811        return false;
812
813    uint64_t port_number = 0;
814
815    do
816    {
817        if (!strcmp(class_name,"NSMachPort"))
818        {
819            uint64_t offset = (ptr_size == 4 ? 12 : 20);
820            Error error;
821            port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error);
822            if (error.Success())
823                break;
824        }
825        if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number))
826            return false;
827    } while (false);
828
829    stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF));
830    return true;
831}
832
833bool
834lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream)
835{
836    ProcessSP process_sp = valobj.GetProcessSP();
837    if (!process_sp)
838        return false;
839
840    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
841
842    if (!runtime)
843        return false;
844
845    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
846
847    if (!descriptor.get() || !descriptor->IsValid())
848        return false;
849
850    uint32_t ptr_size = process_sp->GetAddressByteSize();
851
852    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
853
854    if (!valobj_addr)
855        return false;
856
857    uint32_t count = 0;
858
859    bool is_type_ok = false; // check to see if this is a CFBag we know about
860    if (descriptor->IsCFType())
861    {
862        ConstString type_name(valobj.GetTypeName());
863        if (type_name == ConstString("__CFBag") || type_name == ConstString("const struct __CFBag"))
864        {
865            if (valobj.IsPointerType())
866                is_type_ok = true;
867        }
868    }
869
870    if (is_type_ok == false)
871    {
872        StackFrameSP frame_sp(valobj.GetFrameSP());
873        if (!frame_sp)
874            return false;
875        ValueObjectSP count_sp;
876        StreamString expr;
877        expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
878        if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
879            return false;
880        if (!count_sp)
881            return false;
882        count = count_sp->GetValueAsUnsigned(0);
883    }
884    else
885    {
886        uint32_t offset = 2*ptr_size+4 + valobj_addr;
887        Error error;
888        count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
889        if (error.Fail())
890            return false;
891    }
892    stream.Printf("@\"%u value%s\"",
893                  count,(count == 1 ? "" : "s"));
894    return true;
895}
896
897bool
898lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream)
899{
900    ProcessSP process_sp = valobj.GetProcessSP();
901    if (!process_sp)
902        return false;
903
904    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
905
906    if (!runtime)
907        return false;
908
909    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
910
911    if (!descriptor.get() || !descriptor->IsValid())
912        return false;
913
914    uint32_t ptr_size = process_sp->GetAddressByteSize();
915
916    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
917
918    if (!valobj_addr)
919        return false;
920
921    uint32_t count = 0;
922
923    bool is_type_ok = false; // check to see if this is a CFBag we know about
924    if (descriptor->IsCFType())
925    {
926        ConstString type_name(valobj.GetTypeName());
927        if (type_name == ConstString("__CFMutableBitVector") || type_name == ConstString("__CFBitVector") || type_name == ConstString("CFMutableBitVectorRef") || type_name == ConstString("CFBitVectorRef"))
928        {
929            if (valobj.IsPointerType())
930                is_type_ok = true;
931        }
932    }
933
934    if (is_type_ok == false)
935        return false;
936
937    Error error;
938    count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
939    if (error.Fail())
940        return false;
941    uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
942    addr_t data_ptr = process_sp->ReadPointerFromMemory(valobj_addr+2*ptr_size+2*ptr_size, error);
943    if (error.Fail())
944        return false;
945    // make sure we do not try to read huge amounts of data
946    if (num_bytes > 1024)
947        num_bytes = 1024;
948    DataBufferSP buffer_sp(new DataBufferHeap(num_bytes,0));
949    num_bytes = process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
950    if (error.Fail())
951        return false;
952    for (int byte_idx = 0; byte_idx < num_bytes-1; byte_idx++)
953    {
954        uint8_t byte = buffer_sp->GetBytes()[byte_idx];
955        bool bit0 = (byte & 1) == 1;
956        bool bit1 = (byte & 2) == 2;
957        bool bit2 = (byte & 4) == 4;
958        bool bit3 = (byte & 8) == 8;
959        bool bit4 = (byte & 16) == 16;
960        bool bit5 = (byte & 32) == 32;
961        bool bit6 = (byte & 64) == 64;
962        bool bit7 = (byte & 128) == 128;
963        stream.Printf("%c%c%c%c %c%c%c%c ",
964                      (bit7 ? '1' : '0'),
965                      (bit6 ? '1' : '0'),
966                      (bit5 ? '1' : '0'),
967                      (bit4 ? '1' : '0'),
968                      (bit3 ? '1' : '0'),
969                      (bit2 ? '1' : '0'),
970                      (bit1 ? '1' : '0'),
971                      (bit0 ? '1' : '0'));
972        count -= 8;
973    }
974    {
975        // print the last byte ensuring we do not print spurious bits
976        uint8_t byte = buffer_sp->GetBytes()[num_bytes-1];
977        bool bit0 = (byte & 1) == 1;
978        bool bit1 = (byte & 2) == 2;
979        bool bit2 = (byte & 4) == 4;
980        bool bit3 = (byte & 8) == 8;
981        bool bit4 = (byte & 16) == 16;
982        bool bit5 = (byte & 32) == 32;
983        bool bit6 = (byte & 64) == 64;
984        bool bit7 = (byte & 128) == 128;
985        if (count)
986        {
987            stream.Printf("%c",bit7 ? '1' : '0');
988            count -= 1;
989        }
990        if (count)
991        {
992            stream.Printf("%c",bit6 ? '1' : '0');
993            count -= 1;
994        }
995        if (count)
996        {
997            stream.Printf("%c",bit5 ? '1' : '0');
998            count -= 1;
999        }
1000        if (count)
1001        {
1002            stream.Printf("%c",bit4 ? '1' : '0');
1003            count -= 1;
1004        }
1005        if (count)
1006        {
1007            stream.Printf("%c",bit3 ? '1' : '0');
1008            count -= 1;
1009        }
1010        if (count)
1011        {
1012            stream.Printf("%c",bit2 ? '1' : '0');
1013            count -= 1;
1014        }
1015        if (count)
1016        {
1017            stream.Printf("%c",bit1 ? '1' : '0');
1018            count -= 1;
1019        }
1020        if (count)
1021        {
1022            stream.Printf("%c",bit0 ? '1' : '0');
1023            count -= 1;
1024        }
1025    }
1026    return true;
1027}
1028
1029bool
1030lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream)
1031{
1032    ProcessSP process_sp = valobj.GetProcessSP();
1033    if (!process_sp)
1034        return false;
1035
1036    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1037
1038    if (!runtime)
1039        return false;
1040
1041    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1042
1043    if (!descriptor.get() || !descriptor->IsValid())
1044        return false;
1045
1046    uint32_t ptr_size = process_sp->GetAddressByteSize();
1047
1048    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1049
1050    if (!valobj_addr)
1051        return false;
1052
1053    uint32_t count = 0;
1054
1055    bool is_type_ok = false; // check to see if this is a CFBinaryHeap we know about
1056    if (descriptor->IsCFType())
1057    {
1058        ConstString type_name(valobj.GetTypeName());
1059        if (type_name == ConstString("__CFBinaryHeap") || type_name == ConstString("const struct __CFBinaryHeap"))
1060        {
1061            if (valobj.IsPointerType())
1062                is_type_ok = true;
1063        }
1064    }
1065
1066    if (is_type_ok == false)
1067    {
1068        StackFrameSP frame_sp(valobj.GetFrameSP());
1069        if (!frame_sp)
1070            return false;
1071        ValueObjectSP count_sp;
1072        StreamString expr;
1073        expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
1074        if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
1075            return false;
1076        if (!count_sp)
1077            return false;
1078        count = count_sp->GetValueAsUnsigned(0);
1079    }
1080    else
1081    {
1082        uint32_t offset = 2*ptr_size;
1083        Error error;
1084        count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
1085        if (error.Fail())
1086            return false;
1087    }
1088    stream.Printf("@\"%u item%s\"",
1089                  count,(count == 1 ? "" : "s"));
1090    return true;
1091}
1092
1093bool
1094lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream)
1095{
1096    ProcessSP process_sp = valobj.GetProcessSP();
1097    if (!process_sp)
1098        return false;
1099
1100    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1101
1102    if (!runtime)
1103        return false;
1104
1105    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1106
1107    if (!descriptor.get() || !descriptor->IsValid())
1108        return false;
1109
1110    uint32_t ptr_size = process_sp->GetAddressByteSize();
1111
1112    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1113
1114    if (!valobj_addr)
1115        return false;
1116
1117    const char* class_name = descriptor->GetClassName().GetCString();
1118
1119    if (!class_name || !*class_name)
1120        return false;
1121
1122    uint64_t count = 0;
1123
1124    do {
1125        if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet"))
1126        {
1127            Error error;
1128            uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error);
1129            if (error.Fail())
1130                return false;
1131            // this means the set is empty - count = 0
1132            if ((mode & 1) == 1)
1133            {
1134                count = 0;
1135                break;
1136            }
1137            if ((mode & 2) == 2)
1138                mode = 1; // this means the set only has one range
1139            else
1140                mode = 2; // this means the set has multiple ranges
1141            if (mode == 1)
1142            {
1143                count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error);
1144                if (error.Fail())
1145                    return false;
1146            }
1147            else
1148            {
1149                // read a pointer to the data at 2*ptr_size
1150                count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
1151                if (error.Fail())
1152                    return false;
1153                // read the data at 2*ptr_size from the first location
1154                count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error);
1155                if (error.Fail())
1156                    return false;
1157            }
1158        }
1159        else
1160        {
1161            if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count))
1162                return false;
1163        }
1164    }  while (false);
1165    stream.Printf("%llu index%s",
1166                  count,
1167                  (count == 1 ? "" : "es"));
1168    return true;
1169}
1170
1171bool
1172lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream)
1173{
1174    ProcessSP process_sp = valobj.GetProcessSP();
1175    if (!process_sp)
1176        return false;
1177
1178    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1179
1180    if (!runtime)
1181        return false;
1182
1183    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1184
1185    if (!descriptor.get() || !descriptor->IsValid())
1186        return false;
1187
1188    uint32_t ptr_size = process_sp->GetAddressByteSize();
1189
1190    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1191
1192    if (!valobj_addr)
1193        return false;
1194
1195    const char* class_name = descriptor->GetClassName().GetCString();
1196
1197    if (!class_name || !*class_name)
1198        return false;
1199
1200    if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
1201    {
1202        if (descriptor->IsTagged())
1203        {
1204            // we have a call to get info and value bits in the tagged descriptor. but we prefer not to cast and replicate them
1205            int64_t value = (valobj_addr & ~0x0000000000000000FFL) >> 8;
1206            uint64_t i_bits = (valobj_addr & 0xF0) >> 4;
1207
1208            switch (i_bits)
1209            {
1210                case 0:
1211                    stream.Printf("(char)%hhd",(char)value);
1212                    break;
1213                case 4:
1214                    stream.Printf("(short)%hd",(short)value);
1215                    break;
1216                case 8:
1217                    stream.Printf("(int)%d",(int)value);
1218                    break;
1219                case 12:
1220                    stream.Printf("(long)%" PRId64,value);
1221                    break;
1222                default:
1223                    stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value);
1224                    break;
1225            }
1226            return true;
1227        }
1228        else
1229        {
1230            Error error;
1231            uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
1232            uint64_t data_location = valobj_addr + 2*ptr_size;
1233            uint64_t value = 0;
1234            if (error.Fail())
1235                return false;
1236            switch (data_type)
1237            {
1238                case 1: // 0B00001
1239                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
1240                    if (error.Fail())
1241                        return false;
1242                    stream.Printf("(char)%hhd",(char)value);
1243                    break;
1244                case 2: // 0B0010
1245                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
1246                    if (error.Fail())
1247                        return false;
1248                    stream.Printf("(short)%hd",(short)value);
1249                    break;
1250                case 3: // 0B0011
1251                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
1252                    if (error.Fail())
1253                        return false;
1254                    stream.Printf("(int)%d",(int)value);
1255                    break;
1256                case 17: // 0B10001
1257                    data_location += 8;
1258                case 4: // 0B0100
1259                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
1260                    if (error.Fail())
1261                        return false;
1262                    stream.Printf("(long)%" PRId64,value);
1263                    break;
1264                case 5: // 0B0101
1265                {
1266                    uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
1267                    if (error.Fail())
1268                        return false;
1269                    float flt_value = *((float*)&flt_as_int);
1270                    stream.Printf("(float)%f",flt_value);
1271                    break;
1272                }
1273                case 6: // 0B0110
1274                {
1275                    uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
1276                    if (error.Fail())
1277                        return false;
1278                    double dbl_value = *((double*)&dbl_as_lng);
1279                    stream.Printf("(double)%g",dbl_value);
1280                    break;
1281                }
1282                default:
1283                    stream.Printf("absurd: dt=%d",data_type);
1284                    break;
1285            }
1286            return true;
1287        }
1288    }
1289    else
1290    {
1291        return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
1292    }
1293}
1294
1295static bool
1296ReadAsciiBufferAndDumpToStream (lldb::addr_t location,
1297                                lldb::ProcessSP& process_sp,
1298                                Stream& dest,
1299                                size_t size = 0,
1300                                Error* error = NULL,
1301                                size_t *data_read = NULL,
1302                                char prefix_token = '@',
1303                                char quote = '"')
1304{
1305    Error my_error;
1306    size_t my_data_read;
1307    if (!process_sp || location == 0)
1308        return false;
1309
1310    if (size == 0)
1311        size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
1312
1313    lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
1314
1315    my_data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), size, my_error);
1316
1317    if (error)
1318        *error = my_error;
1319    if (data_read)
1320        *data_read = my_data_read;
1321
1322    if (my_error.Fail())
1323        return false;
1324    if (my_data_read)
1325        dest.Printf("%c%c%s%c",prefix_token,quote,(char*)buffer_sp->GetBytes(),quote);
1326
1327    return true;
1328}
1329
1330bool
1331lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
1332{
1333    ProcessSP process_sp = valobj.GetProcessSP();
1334    if (!process_sp)
1335        return false;
1336
1337    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1338
1339    if (!runtime)
1340        return false;
1341
1342    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1343
1344    if (!descriptor.get() || !descriptor->IsValid())
1345        return false;
1346
1347    uint32_t ptr_size = process_sp->GetAddressByteSize();
1348
1349    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1350
1351    if (!valobj_addr)
1352        return false;
1353
1354    const char* class_name = descriptor->GetClassName().GetCString();
1355
1356    if (!class_name || !*class_name)
1357        return false;
1358
1359    uint64_t info_bits_location = valobj_addr + ptr_size;
1360    if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
1361        info_bits_location += 3;
1362
1363    Error error;
1364
1365    uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error);
1366    if (error.Fail())
1367        return false;
1368
1369    bool is_mutable = (info_bits & 1) == 1;
1370    bool is_inline = (info_bits & 0x60) == 0;
1371    bool has_explicit_length = (info_bits & (1 | 4)) != 4;
1372    bool is_unicode = (info_bits & 0x10) == 0x10;
1373    bool is_special = strcmp(class_name,"NSPathStore2") == 0;
1374
1375    if (strcmp(class_name,"NSString") &&
1376        strcmp(class_name,"CFStringRef") &&
1377        strcmp(class_name,"CFMutableStringRef") &&
1378        strcmp(class_name,"__NSCFConstantString") &&
1379        strcmp(class_name,"__NSCFString") &&
1380        strcmp(class_name,"NSCFConstantString") &&
1381        strcmp(class_name,"NSCFString") &&
1382        strcmp(class_name,"NSPathStore2"))
1383    {
1384        // not one of us - but tell me class name
1385        stream.Printf("class name = %s",class_name);
1386        return true;
1387    }
1388
1389    if (is_mutable)
1390    {
1391        uint64_t location = 2 * ptr_size + valobj_addr;
1392        location = process_sp->ReadPointerFromMemory(location, error);
1393        if (error.Fail())
1394            return false;
1395        if (has_explicit_length and is_unicode)
1396            return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8,location, process_sp, stream, '@');
1397        else
1398            return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream);
1399    }
1400    else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable)
1401    {
1402        uint64_t location = 3 * ptr_size + valobj_addr;
1403        return ReadAsciiBufferAndDumpToStream(location,process_sp,stream);
1404    }
1405    else if (is_unicode)
1406    {
1407        uint64_t location = valobj_addr + 2*ptr_size;
1408        if (is_inline)
1409        {
1410            if (!has_explicit_length)
1411            {
1412                stream.Printf("found new combo");
1413                return true;
1414            }
1415            else
1416                location += ptr_size;
1417                }
1418        else
1419        {
1420            location = process_sp->ReadPointerFromMemory(location, error);
1421            if (error.Fail())
1422                return false;
1423        }
1424        return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
1425    }
1426    else if (is_special)
1427    {
1428        uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8);
1429        return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
1430    }
1431    else if (is_inline)
1432    {
1433        uint64_t location = valobj_addr + 2*ptr_size;
1434        if (!has_explicit_length)
1435            location++;
1436        return ReadAsciiBufferAndDumpToStream(location,process_sp,stream);
1437    }
1438    else
1439    {
1440        uint64_t location = valobj_addr + 2*ptr_size;
1441        location = process_sp->ReadPointerFromMemory(location, error);
1442        if (error.Fail())
1443            return false;
1444        return ReadAsciiBufferAndDumpToStream(location,process_sp,stream);
1445    }
1446
1447    stream.Printf("class name = %s",class_name);
1448    return true;
1449
1450}
1451
1452bool
1453lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1454{
1455    TargetSP target_sp(valobj.GetTargetSP());
1456    if (!target_sp)
1457        return false;
1458    uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
1459    uint64_t pointee = valobj.GetValueAsUnsigned(0);
1460    if (!pointee)
1461        return false;
1462    pointee += addr_size;
1463    ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
1464    ExecutionContext exe_ctx(target_sp,false);
1465    ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointee, exe_ctx, type));
1466    if (!child_ptr_sp)
1467        return false;
1468    DataExtractor data;
1469    child_ptr_sp->GetData(data);
1470    ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type));
1471    child_sp->GetValueAsUnsigned(0);
1472    if (child_sp)
1473        return NSStringSummaryProvider(*child_sp, stream);
1474    return false;
1475}
1476
1477bool
1478lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1479{
1480    return NSAttributedStringSummaryProvider(valobj, stream);
1481}
1482
1483bool
1484lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream)
1485{
1486    stream.Printf("%s",valobj.GetObjectDescription());
1487    return true;
1488}
1489
1490bool
1491lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream)
1492{
1493    ProcessSP process_sp = valobj.GetProcessSP();
1494    if (!process_sp)
1495        return false;
1496
1497    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1498
1499    if (!runtime)
1500        return false;
1501
1502    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1503
1504    if (!descriptor.get() || !descriptor->IsValid())
1505        return false;
1506
1507    uint32_t ptr_size = process_sp->GetAddressByteSize();
1508
1509    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1510
1511    if (!valobj_addr)
1512        return false;
1513
1514    const char* class_name = descriptor->GetClassName().GetCString();
1515
1516    if (!class_name || !*class_name)
1517        return false;
1518
1519    if (strcmp(class_name, "NSURL") == 0)
1520    {
1521        uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit)
1522        uint64_t offset_base = offset_text + ptr_size;
1523        ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
1524        ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
1525        ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
1526        if (!text)
1527            return false;
1528        if (text->GetValueAsUnsigned(0) == 0)
1529            return false;
1530        StreamString summary;
1531        if (!NSStringSummaryProvider(*text, summary))
1532            return false;
1533        if (base && base->GetValueAsUnsigned(0))
1534        {
1535            if (summary.GetSize() > 0)
1536                summary.GetString().resize(summary.GetSize()-1);
1537            summary.Printf(" -- ");
1538            StreamString base_summary;
1539            if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0)
1540                summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
1541        }
1542        if (summary.GetSize())
1543        {
1544            stream.Printf("%s",summary.GetData());
1545            return true;
1546        }
1547    }
1548    else
1549    {
1550        return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream);
1551    }
1552    return false;
1553}
1554
1555bool
1556lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream)
1557{
1558    const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(),
1559                                                            valobj.GetClangAST(),
1560                                                            NULL);
1561
1562    ValueObjectSP real_guy_sp = valobj.GetSP();
1563
1564    if (type_info & ClangASTContext::eTypeIsPointer)
1565    {
1566        Error err;
1567        real_guy_sp = valobj.Dereference(err);
1568        if (err.Fail() || !real_guy_sp)
1569            return false;
1570    }
1571    else if (type_info & ClangASTContext::eTypeIsReference)
1572    {
1573        real_guy_sp =  valobj.GetChildAtIndex(0, true);
1574        if (!real_guy_sp)
1575            return false;
1576    }
1577    uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
1578    if (value == 0)
1579    {
1580        stream.Printf("NO");
1581        return true;
1582    }
1583    stream.Printf("YES");
1584    return true;
1585}
1586
1587template <bool is_sel_ptr>
1588bool
1589lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream)
1590{
1591    lldb::ValueObjectSP valobj_sp;
1592
1593    if (!valobj.GetClangAST())
1594        return false;
1595    void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr();
1596    if (!char_opaque_type)
1597        return false;
1598    ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type));
1599
1600    ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1601
1602    if (is_sel_ptr)
1603    {
1604        lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1605        if (data_address == LLDB_INVALID_ADDRESS)
1606            return false;
1607        valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar);
1608    }
1609    else
1610    {
1611        DataExtractor data;
1612        valobj.GetData(data);
1613        valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
1614    }
1615
1616    if (!valobj_sp)
1617        return false;
1618
1619    stream.Printf("%s",valobj_sp->GetSummaryAsCString());
1620    return true;
1621}
1622
1623// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
1624// this call gives the POSIX equivalent of the Cocoa epoch
1625time_t
1626GetOSXEpoch ()
1627{
1628    static time_t epoch = 0;
1629    if (!epoch)
1630    {
1631        tzset();
1632        tm tm_epoch;
1633        tm_epoch.tm_sec = 0;
1634        tm_epoch.tm_hour = 0;
1635        tm_epoch.tm_min = 0;
1636        tm_epoch.tm_mon = 0;
1637        tm_epoch.tm_mday = 1;
1638        tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why.
1639        tm_epoch.tm_isdst = -1;
1640        tm_epoch.tm_gmtoff = 0;
1641        tm_epoch.tm_zone = NULL;
1642        epoch = timegm(&tm_epoch);
1643    }
1644    return epoch;
1645}
1646
1647bool
1648lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream)
1649{
1650    ProcessSP process_sp = valobj.GetProcessSP();
1651    if (!process_sp)
1652        return false;
1653
1654    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1655
1656    if (!runtime)
1657        return false;
1658
1659    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
1660
1661    if (!descriptor.get() || !descriptor->IsValid())
1662        return false;
1663
1664    uint32_t ptr_size = process_sp->GetAddressByteSize();
1665
1666    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1667
1668    if (!valobj_addr)
1669        return false;
1670
1671    uint64_t date_value_bits = 0;
1672    double date_value = 0.0;
1673
1674    const char* class_name = descriptor->GetClassName().GetCString();
1675
1676    if (!class_name || !*class_name)
1677        return false;
1678
1679    if (strcmp(class_name,"NSDate") == 0 ||
1680        strcmp(class_name,"__NSDate") == 0 ||
1681        strcmp(class_name,"__NSTaggedDate") == 0)
1682    {
1683        if (descriptor->IsTagged())
1684        {
1685            uint64_t info_bits = (valobj_addr & 0xF0ULL) >> 4;
1686            uint64_t value_bits = (valobj_addr & ~0x0000000000000000FFULL) >> 8;
1687            date_value_bits = ((value_bits << 8) | (info_bits << 4));
1688            date_value = *((double*)&date_value_bits);
1689        }
1690        else
1691        {
1692            Error error;
1693            date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
1694            date_value = *((double*)&date_value_bits);
1695            if (error.Fail())
1696                return false;
1697        }
1698    }
1699    else if (!strcmp(class_name,"NSCalendarDate"))
1700    {
1701        Error error;
1702        date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
1703        date_value = *((double*)&date_value_bits);
1704        if (error.Fail())
1705            return false;
1706    }
1707    else
1708    {
1709        if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
1710            return false;
1711        date_value = *((double*)&date_value_bits);
1712    }
1713    if (date_value == -63114076800)
1714    {
1715        stream.Printf("0001-12-30 00:00:00 +0000");
1716        return true;
1717    }
1718    // this snippet of code assumes that time_t == seconds since Jan-1-1970
1719    // this is generally true and POSIXly happy, but might break if a library
1720    // vendor decides to get creative
1721    time_t epoch = GetOSXEpoch();
1722    epoch = epoch + (time_t)date_value;
1723    tm *tm_date = localtime(&epoch);
1724    if (!tm_date)
1725        return false;
1726    std::string buffer(1024,0);
1727    if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
1728        return false;
1729    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());
1730    return true;
1731}
1732
1733bool
1734lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream)
1735{
1736    time_t epoch = GetOSXEpoch();
1737    epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0);
1738    tm *tm_date = localtime(&epoch);
1739    if (!tm_date)
1740        return false;
1741    std::string buffer(1024,0);
1742    if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
1743        return false;
1744    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());
1745    return true;
1746}
1747
1748size_t
1749lldb_private::formatters::ExtractIndexFromString (const char* item_name)
1750{
1751    if (!item_name || !*item_name)
1752        return UINT32_MAX;
1753    if (*item_name != '[')
1754        return UINT32_MAX;
1755    item_name++;
1756    char* endptr = NULL;
1757    unsigned long int idx = ::strtoul(item_name, &endptr, 0);
1758    if (idx == 0 && endptr == item_name)
1759        return UINT32_MAX;
1760    if (idx == ULONG_MAX)
1761        return UINT32_MAX;
1762    return idx;
1763}
1764
1765lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
1766                                                                                            ConstString item_name) :
1767SyntheticChildrenFrontEnd(*valobj_sp.get()),
1768m_exe_ctx_ref(),
1769m_item_name(item_name),
1770m_item_sp()
1771{
1772    if (valobj_sp)
1773        Update();
1774}
1775
1776bool
1777lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update()
1778{
1779    ValueObjectSP valobj_sp = m_backend.GetSP();
1780    if (!valobj_sp)
1781        return false;
1782
1783    if (!valobj_sp)
1784        return false;
1785
1786    ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true));
1787    if (!item_ptr)
1788        return false;
1789    if (item_ptr->GetValueAsUnsigned(0) == 0)
1790        return false;
1791    Error err;
1792    m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1793    m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, ClangASTType(item_ptr->GetClangAST(),ClangASTType::GetPointeeType(item_ptr->GetClangType())));
1794    if (err.Fail())
1795        m_item_sp.reset();
1796    return (m_item_sp.get() != NULL);
1797}
1798
1799size_t
1800lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren ()
1801{
1802    return 1;
1803}
1804
1805lldb::ValueObjectSP
1806lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1807{
1808    if (idx == 0)
1809        return m_item_sp;
1810    return lldb::ValueObjectSP();
1811}
1812
1813bool
1814lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren ()
1815{
1816    return true;
1817}
1818
1819size_t
1820lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1821{
1822    if (name == ConstString("item"))
1823        return 0;
1824    return UINT32_MAX;
1825}
1826
1827lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd ()
1828{
1829}
1830
1831template bool
1832lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
1833
1834template bool
1835lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
1836
1837template bool
1838lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ;
1839
1840template bool
1841lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ;
1842