CXXFormatterFunctions.cpp revision d32acdb74c50f6fc3a2aab0619a75f2bc4c05a30
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 "lldb/DataFormatters/CXXFormatterFunctions.h"
13
14#include "llvm/Support/ConvertUTF.h"
15
16#include "lldb/Core/DataBufferHeap.h"
17#include "lldb/Core/Error.h"
18#include "lldb/Core/Stream.h"
19#include "lldb/Core/ValueObject.h"
20#include "lldb/Core/ValueObjectConstResult.h"
21#include "lldb/Host/Endian.h"
22#include "lldb/Symbol/ClangASTContext.h"
23#include "lldb/Target/ObjCLanguageRuntime.h"
24#include "lldb/Target/Target.h"
25
26using namespace lldb;
27using namespace lldb_private;
28using namespace lldb_private::formatters;
29
30bool
31lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
32                                                          const char* target_type,
33                                                          const char* selector,
34                                                          uint64_t &value)
35{
36    if (!target_type || !*target_type)
37        return false;
38    if (!selector || !*selector)
39        return false;
40    StreamString expr;
41    expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
42    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
43    lldb::ValueObjectSP result_sp;
44    Target* target = exe_ctx.GetTargetPtr();
45    StackFrame* stack_frame = exe_ctx.GetFramePtr();
46    if (!target || !stack_frame)
47        return false;
48
49    EvaluateExpressionOptions options;
50    options.SetCoerceToId(false)
51    .SetUnwindOnError(true)
52    .SetKeepInMemory(true);
53
54    target->EvaluateExpression(expr.GetData(),
55                               stack_frame,
56                               result_sp,
57                               options);
58    if (!result_sp)
59        return false;
60    value = result_sp->GetValueAsUnsigned(0);
61    return true;
62}
63
64bool
65lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj,
66                                                            const char* target_type,
67                                                            const char* selector,
68                                                            Stream &stream)
69{
70    if (!target_type || !*target_type)
71        return false;
72    if (!selector || !*selector)
73        return false;
74    StreamString expr;
75    expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
76    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
77    lldb::ValueObjectSP result_sp;
78    Target* target = exe_ctx.GetTargetPtr();
79    StackFrame* stack_frame = exe_ctx.GetFramePtr();
80    if (!target || !stack_frame)
81        return false;
82
83    EvaluateExpressionOptions options;
84    options.SetCoerceToId(false)
85    .SetUnwindOnError(true)
86    .SetKeepInMemory(true)
87    .SetUseDynamic(lldb::eDynamicCanRunTarget);
88
89    target->EvaluateExpression(expr.GetData(),
90                               stack_frame,
91                               result_sp,
92                               options);
93    if (!result_sp)
94        return false;
95    stream.Printf("%s",result_sp->GetSummaryAsCString());
96    return true;
97}
98
99lldb::ValueObjectSP
100lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
101                                                const char* return_type,
102                                                const char* selector,
103                                                uint64_t index)
104{
105    lldb::ValueObjectSP valobj_sp;
106    if (!return_type || !*return_type)
107        return valobj_sp;
108    if (!selector || !*selector)
109        return valobj_sp;
110    StreamString expr_path_stream;
111    valobj.GetExpressionPath(expr_path_stream, false);
112    StreamString expr;
113    expr.Printf("(%s)[%s %s:%" PRId64 "]",return_type,expr_path_stream.GetData(),selector,index);
114    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
115    lldb::ValueObjectSP result_sp;
116    Target* target = exe_ctx.GetTargetPtr();
117    StackFrame* stack_frame = exe_ctx.GetFramePtr();
118    if (!target || !stack_frame)
119        return valobj_sp;
120
121    EvaluateExpressionOptions options;
122    options.SetCoerceToId(false)
123    .SetUnwindOnError(true)
124    .SetKeepInMemory(true)
125    .SetUseDynamic(lldb::eDynamicCanRunTarget);
126
127    target->EvaluateExpression(expr.GetData(),
128                               stack_frame,
129                               valobj_sp,
130                               options);
131    return valobj_sp;
132}
133
134lldb::ValueObjectSP
135lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
136                                                const char* return_type,
137                                                const char* selector,
138                                                const char* key)
139{
140    lldb::ValueObjectSP valobj_sp;
141    if (!return_type || !*return_type)
142        return valobj_sp;
143    if (!selector || !*selector)
144        return valobj_sp;
145    if (!key || !*key)
146        return valobj_sp;
147    StreamString expr_path_stream;
148    valobj.GetExpressionPath(expr_path_stream, false);
149    StreamString expr;
150    expr.Printf("(%s)[%s %s:%s]",return_type,expr_path_stream.GetData(),selector,key);
151    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
152    lldb::ValueObjectSP result_sp;
153    Target* target = exe_ctx.GetTargetPtr();
154    StackFrame* stack_frame = exe_ctx.GetFramePtr();
155    if (!target || !stack_frame)
156        return valobj_sp;
157
158    EvaluateExpressionOptions options;
159    options.SetCoerceToId(false)
160    .SetUnwindOnError(true)
161    .SetKeepInMemory(true)
162    .SetUseDynamic(lldb::eDynamicCanRunTarget);
163
164    target->EvaluateExpression(expr.GetData(),
165                               stack_frame,
166                               valobj_sp,
167                               options);
168    return valobj_sp;
169}
170
171// use this call if you already have an LLDB-side buffer for the data
172template<typename SourceDataType>
173static bool
174DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
175                                                            const SourceDataType*,
176                                                            UTF8**,
177                                                            UTF8*,
178                                                            ConversionFlags),
179                       DataExtractor& data,
180                       Stream& stream,
181                       char prefix_token = '@',
182                       char quote = '"',
183                       int sourceSize = 0)
184{
185    if (prefix_token != 0)
186        stream.Printf("%c",prefix_token);
187    if (quote != 0)
188        stream.Printf("%c",quote);
189    if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
190    {
191        const int bufferSPSize = data.GetByteSize();
192        if (sourceSize == 0)
193        {
194            const int origin_encoding = 8*sizeof(SourceDataType);
195            sourceSize = bufferSPSize/(origin_encoding / 4);
196        }
197
198        SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart();
199        SourceDataType *data_end_ptr = data_ptr + sourceSize;
200
201        while (data_ptr < data_end_ptr)
202        {
203            if (!*data_ptr)
204            {
205                data_end_ptr = data_ptr;
206                break;
207            }
208            data_ptr++;
209        }
210
211        data_ptr = (SourceDataType*)data.GetDataStart();
212
213        lldb::DataBufferSP utf8_data_buffer_sp;
214        UTF8* utf8_data_ptr = nullptr;
215        UTF8* utf8_data_end_ptr = nullptr;
216
217        if (ConvertFunction)
218        {
219            utf8_data_buffer_sp.reset(new DataBufferHeap(bufferSPSize,0));
220            utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
221            utf8_data_end_ptr = utf8_data_ptr + bufferSPSize;
222            ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
223            utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
224        }
225        else
226        {
227            // just copy the pointers - the cast is necessary to make the compiler happy
228            // but this should only happen if we are reading UTF8 data
229            utf8_data_ptr = (UTF8*)data_ptr;
230            utf8_data_end_ptr = (UTF8*)data_end_ptr;
231        }
232
233        // since we tend to accept partial data (and even partially malformed data)
234        // we might end up with no NULL terminator before the end_ptr
235        // hence we need to take a slower route and ensure we stay within boundaries
236        for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++)
237        {
238            if (!*utf8_data_ptr)
239                break;
240            stream.Printf("%c",*utf8_data_ptr);
241        }
242    }
243    if (quote != 0)
244        stream.Printf("%c",quote);
245    return true;
246}
247
248template<typename SourceDataType>
249static bool
250ReadUTFBufferAndDumpToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
251                                                                   const SourceDataType*,
252                                                                   UTF8**,
253                                                                   UTF8*,
254                                                                   ConversionFlags),
255                              uint64_t location,
256                              const ProcessSP& process_sp,
257                              Stream& stream,
258                              char prefix_token = '@',
259                              char quote = '"',
260                              int sourceSize = 0)
261{
262    if (location == 0 || location == LLDB_INVALID_ADDRESS)
263        return false;
264    if (!process_sp)
265        return false;
266
267    const int origin_encoding = 8*sizeof(SourceDataType);
268    if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
269        return false;
270    // if not UTF8, I need a conversion function to return proper UTF8
271    if (origin_encoding != 8 && !ConvertFunction)
272        return false;
273
274    if (sourceSize == 0)
275        sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
276    const int bufferSPSize = sourceSize * (origin_encoding >> 2);
277
278    Error error;
279    lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
280
281    if (!buffer_sp->GetBytes())
282        return false;
283
284    size_t data_read = process_sp->ReadMemoryFromInferior(location, (char*)buffer_sp->GetBytes(), bufferSPSize, error);
285    if (error.Fail() || data_read == 0)
286    {
287        stream.Printf("unable to read data");
288        return true;
289    }
290
291    DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
292
293    return DumpUTFBufferToStream(ConvertFunction, data, stream, prefix_token, quote, sourceSize);
294}
295
296bool
297lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream)
298{
299    ProcessSP process_sp = valobj.GetProcessSP();
300    if (!process_sp)
301        return false;
302
303    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
304
305    if (!valobj_addr)
306        return false;
307
308    if (!ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8,valobj_addr,
309                                                                 process_sp,
310                                                                 stream,
311                                                                 'u'))
312    {
313        stream.Printf("Summary Unavailable");
314        return true;
315    }
316
317    return true;
318}
319
320bool
321lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream)
322{
323    ProcessSP process_sp = valobj.GetProcessSP();
324    if (!process_sp)
325        return false;
326
327    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
328
329    if (!valobj_addr)
330        return false;
331
332    if (!ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8,valobj_addr,
333                                                                 process_sp,
334                                                                 stream,
335                                                                 'U'))
336    {
337        stream.Printf("Summary Unavailable");
338        return true;
339    }
340
341    return true;
342}
343
344bool
345lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream)
346{
347    ProcessSP process_sp = valobj.GetProcessSP();
348    if (!process_sp)
349        return false;
350
351    lldb::addr_t data_addr = 0;
352
353    if (valobj.IsPointerType())
354        data_addr = valobj.GetValueAsUnsigned(0);
355    else if (valobj.IsArrayType())
356        data_addr = valobj.GetAddressOf();
357
358    if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS)
359        return false;
360
361    clang::ASTContext* ast = valobj.GetClangAST();
362
363    if (!ast)
364        return false;
365
366    uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
367
368    switch (wchar_size)
369    {
370        case 8:
371            // utf 8
372            return ReadUTFBufferAndDumpToStream<UTF8>(nullptr, data_addr,
373                                                               process_sp,
374                                                               stream,
375                                                               'L');
376        case 16:
377            // utf 16
378            return ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8, data_addr,
379                                                                           process_sp,
380                                                                           stream,
381                                                                           'L');
382        case 32:
383            // utf 32
384            return ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8, data_addr,
385                                                                           process_sp,
386                                                                           stream,
387                                                                           'L');
388        default:
389            stream.Printf("size for wchar_t is not valid");
390            return true;
391    }
392    return true;
393}
394
395bool
396lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
397{
398    DataExtractor data;
399    valobj.GetData(data);
400
401    std::string value;
402    valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
403    if (!value.empty())
404        stream.Printf("%s ", value.c_str());
405
406    return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1);
407}
408
409bool
410lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
411{
412    DataExtractor data;
413    valobj.GetData(data);
414
415    std::string value;
416    valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
417    if (!value.empty())
418        stream.Printf("%s ", value.c_str());
419
420    return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1);
421}
422
423bool
424lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
425{
426    DataExtractor data;
427    valobj.GetData(data);
428
429    clang::ASTContext* ast = valobj.GetClangAST();
430
431    if (!ast)
432        return false;
433
434    std::string value;
435
436    uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
437
438    switch (wchar_size)
439    {
440        case 8:
441            // utf 8
442            valobj.GetValueAsCString(lldb::eFormatChar, value);
443            if (!value.empty())
444                stream.Printf("%s ", value.c_str());
445            return DumpUTFBufferToStream<UTF8>(nullptr,
446                                               data,
447                                               stream,
448                                               'L',
449                                               '\'',
450                                               1);
451        case 16:
452            // utf 16
453            valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
454            if (!value.empty())
455                stream.Printf("%s ", value.c_str());
456            return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,
457                                                data,
458                                                stream,
459                                                'L',
460                                                '\'',
461                                                1);
462        case 32:
463            // utf 32
464            valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
465            if (!value.empty())
466                stream.Printf("%s ", value.c_str());
467            return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,
468                                                data,
469                                                stream,
470                                                'L',
471                                                '\'',
472                                                1);
473        default:
474            stream.Printf("size for wchar_t is not valid");
475            return true;
476    }
477    return true;
478}
479
480// this function extracts information from a libcxx std::basic_string<>
481// irregardless of template arguments. it reports the size (in item count not bytes)
482// and the location in memory where the string data can be found
483static bool
484ExtractLibcxxStringInfo (ValueObject& valobj,
485                         ValueObjectSP &location_sp,
486                         uint64_t& size)
487{
488    ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
489    if (!D)
490        return false;
491
492    ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
493    if (!size_mode)
494        return false;
495
496    uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0));
497
498    if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline
499    {
500        ValueObjectSP s(D->GetChildAtIndex(1, true));
501        if (!s)
502            return false;
503        size = ((size_mode_value >> 1) % 256);
504        location_sp = s->GetChildAtIndex(1, true);
505        return (location_sp.get() != nullptr);
506    }
507    else
508    {
509        ValueObjectSP l(D->GetChildAtIndex(0, true));
510        if (!l)
511            return false;
512        location_sp = l->GetChildAtIndex(2, true);
513        ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
514        if (!size_vo || !location_sp)
515            return false;
516        size = size_vo->GetValueAsUnsigned(0);
517        return true;
518    }
519}
520
521bool
522lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
523{
524    uint64_t size = 0;
525    ValueObjectSP location_sp((ValueObject*)nullptr);
526    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
527        return false;
528    if (size == 0)
529    {
530        stream.Printf("L\"\"");
531        return true;
532    }
533    if (!location_sp)
534        return false;
535    return WCharStringSummaryProvider(*location_sp.get(), stream);
536}
537
538bool
539lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
540{
541    uint64_t size = 0;
542    ValueObjectSP location_sp((ValueObject*)nullptr);
543    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
544        return false;
545    if (size == 0)
546    {
547        stream.Printf("\"\"");
548        return true;
549    }
550    if (!location_sp)
551        return false;
552    Error error;
553    if (location_sp->ReadPointedString(stream,
554                                       error,
555                                       0, // max length is decided by the settings
556                                       false) == 0) // do not honor array (terminates on first 0 byte even for a char[])
557        stream.Printf("\"\""); // if nothing was read, print an empty string
558    return error.Success();
559}
560
561bool
562lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream)
563{
564    ProcessSP process_sp = valobj.GetProcessSP();
565    if (!process_sp)
566        return false;
567
568    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
569
570    if (!runtime)
571        return false;
572
573    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj.GetValueAsUnsigned(0)));
574
575    if (!descriptor.get() || !descriptor->IsValid())
576        return false;
577
578    const char* class_name = descriptor->GetClassName().GetCString();
579
580    if (!class_name || !*class_name)
581        return false;
582
583    stream.Printf("%s",class_name);
584    return true;
585}
586
587template<bool needs_at>
588bool
589lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream)
590{
591    ProcessSP process_sp = valobj.GetProcessSP();
592    if (!process_sp)
593        return false;
594
595    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
596
597    if (!runtime)
598        return false;
599
600    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
601
602    if (!descriptor.get() || !descriptor->IsValid())
603        return false;
604
605    bool is_64bit = (process_sp->GetAddressByteSize() == 8);
606    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
607
608    if (!valobj_addr)
609        return false;
610
611    uint64_t value = 0;
612
613    const char* class_name = descriptor->GetClassName().GetCString();
614
615    if (!class_name || !*class_name)
616        return false;
617
618    if (!strcmp(class_name,"NSConcreteData") ||
619        !strcmp(class_name,"NSConcreteMutableData") ||
620        !strcmp(class_name,"__NSCFData"))
621    {
622        uint32_t offset = (is_64bit ? 16 : 8);
623        Error error;
624        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
625        if (error.Fail())
626            return false;
627    }
628    else
629    {
630        if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
631            return false;
632    }
633
634    stream.Printf("%s%" PRIu64 " byte%s%s",
635                  (needs_at ? "@\"" : ""),
636                  value,
637                  (value > 1 ? "s" : ""),
638                  (needs_at ? "\"" : ""));
639
640    return true;
641}
642
643static bool
644ReadAsciiBufferAndDumpToStream (lldb::addr_t location,
645                                lldb::ProcessSP& process_sp,
646                                Stream& dest,
647                                size_t size = 0,
648                                Error* error = NULL,
649                                size_t *data_read = NULL,
650                                char prefix_token = '@',
651                                char quote = '"')
652{
653    Error my_error;
654    size_t my_data_read;
655    if (!process_sp || location == 0)
656        return false;
657
658    if (size == 0)
659        size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
660
661    lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
662
663    my_data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), size, my_error);
664
665    if (error)
666        *error = my_error;
667    if (data_read)
668        *data_read = my_data_read;
669
670    if (my_error.Fail())
671        return false;
672    if (my_data_read)
673        dest.Printf("%c%c%s%c",prefix_token,quote,(char*)buffer_sp->GetBytes(),quote);
674
675    return true;
676}
677
678bool
679lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
680{
681    ProcessSP process_sp = valobj.GetProcessSP();
682    if (!process_sp)
683        return false;
684
685    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
686
687    if (!runtime)
688        return false;
689
690    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
691
692    if (!descriptor.get() || !descriptor->IsValid())
693        return false;
694
695    uint32_t ptr_size = process_sp->GetAddressByteSize();
696
697    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
698
699    if (!valobj_addr)
700        return false;
701
702    const char* class_name = descriptor->GetClassName().GetCString();
703
704    if (!class_name || !*class_name)
705        return false;
706
707    uint64_t info_bits_location = valobj_addr + ptr_size;
708    if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
709        info_bits_location += 3;
710
711    Error error;
712
713    uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error);
714    if (error.Fail())
715        return false;
716
717    bool is_mutable = (info_bits & 1) == 1;
718    bool is_inline = (info_bits & 0x60) == 0;
719    bool has_explicit_length = (info_bits & (1 | 4)) != 4;
720    bool is_unicode = (info_bits & 0x10) == 0x10;
721    bool is_special = strcmp(class_name,"NSPathStore2") == 0;
722
723    if (strcmp(class_name,"NSString") &&
724        strcmp(class_name,"CFStringRef") &&
725        strcmp(class_name,"CFMutableStringRef") &&
726        strcmp(class_name,"__NSCFConstantString") &&
727        strcmp(class_name,"__NSCFString") &&
728        strcmp(class_name,"NSCFConstantString") &&
729        strcmp(class_name,"NSCFString") &&
730        strcmp(class_name,"NSPathStore2"))
731    {
732        // not one of us - but tell me class name
733        stream.Printf("class name = %s",class_name);
734        return true;
735    }
736
737    if (is_mutable)
738    {
739        uint64_t location = 2 * ptr_size + valobj_addr;
740        location = process_sp->ReadPointerFromMemory(location, error);
741        if (error.Fail())
742            return false;
743        if (has_explicit_length and is_unicode)
744            return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8,location, process_sp, stream, '@');
745        else
746            return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream);
747    }
748    else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable)
749    {
750        uint64_t location = 3 * ptr_size + valobj_addr;
751        return ReadAsciiBufferAndDumpToStream(location,process_sp,stream);
752    }
753    else if (is_unicode)
754    {
755        uint64_t location = valobj_addr + 2*ptr_size;
756        if (is_inline)
757        {
758            if (!has_explicit_length)
759            {
760                stream.Printf("found new combo");
761                return true;
762            }
763            else
764                location += ptr_size;
765                }
766        else
767        {
768            location = process_sp->ReadPointerFromMemory(location, error);
769            if (error.Fail())
770                return false;
771        }
772        return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
773    }
774    else if (is_special)
775    {
776        uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8);
777        return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
778    }
779    else if (is_inline)
780    {
781        uint64_t location = valobj_addr + 2*ptr_size;
782        if (!has_explicit_length)
783            location++;
784        return ReadAsciiBufferAndDumpToStream(location,process_sp,stream);
785    }
786    else
787    {
788        uint64_t location = valobj_addr + 2*ptr_size;
789        location = process_sp->ReadPointerFromMemory(location, error);
790        if (error.Fail())
791            return false;
792        return ReadAsciiBufferAndDumpToStream(location,process_sp,stream);
793    }
794
795    stream.Printf("class name = %s",class_name);
796    return true;
797
798}
799
800bool
801lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
802{
803    TargetSP target_sp(valobj.GetTargetSP());
804    if (!target_sp)
805        return false;
806    uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
807    uint64_t pointee = valobj.GetValueAsUnsigned(0);
808    if (!pointee)
809        return false;
810    pointee += addr_size;
811    ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
812    ExecutionContext exe_ctx(target_sp,false);
813    ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointee, exe_ctx, type));
814    if (!child_ptr_sp)
815        return false;
816    DataExtractor data;
817    child_ptr_sp->GetData(data);
818    ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type));
819    child_sp->GetValueAsUnsigned(0);
820    if (child_sp)
821        return NSStringSummaryProvider(*child_sp, stream);
822    return false;
823}
824
825bool
826lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
827{
828    return NSAttributedStringSummaryProvider(valobj, stream);
829}
830
831bool
832lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream)
833{
834    stream.Printf("%s",valobj.GetObjectDescription());
835    return true;
836}
837
838bool
839lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream)
840{
841    const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(),
842                                                            valobj.GetClangAST(),
843                                                            NULL);
844
845    ValueObjectSP real_guy_sp = valobj.GetSP();
846
847    if (type_info & ClangASTContext::eTypeIsPointer)
848    {
849        Error err;
850        real_guy_sp = valobj.Dereference(err);
851        if (err.Fail() || !real_guy_sp)
852            return false;
853    }
854    else if (type_info & ClangASTContext::eTypeIsReference)
855    {
856        real_guy_sp =  valobj.GetChildAtIndex(0, true);
857        if (!real_guy_sp)
858            return false;
859    }
860    uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
861    if (value == 0)
862    {
863        stream.Printf("NO");
864        return true;
865    }
866    stream.Printf("YES");
867    return true;
868}
869
870template <bool is_sel_ptr>
871bool
872lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream)
873{
874    lldb::ValueObjectSP valobj_sp;
875
876    if (!valobj.GetClangAST())
877        return false;
878    void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr();
879    if (!char_opaque_type)
880        return false;
881    ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type));
882
883    ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
884
885    if (is_sel_ptr)
886    {
887        lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
888        if (data_address == LLDB_INVALID_ADDRESS)
889            return false;
890        valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar);
891    }
892    else
893    {
894        DataExtractor data;
895        valobj.GetData(data);
896        valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
897    }
898
899    if (!valobj_sp)
900        return false;
901
902    stream.Printf("%s",valobj_sp->GetSummaryAsCString());
903    return true;
904}
905
906// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
907// this call gives the POSIX equivalent of the Cocoa epoch
908time_t
909lldb_private::formatters::GetOSXEpoch ()
910{
911    static time_t epoch = 0;
912    if (!epoch)
913    {
914        tzset();
915        tm tm_epoch;
916        tm_epoch.tm_sec = 0;
917        tm_epoch.tm_hour = 0;
918        tm_epoch.tm_min = 0;
919        tm_epoch.tm_mon = 0;
920        tm_epoch.tm_mday = 1;
921        tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why.
922        tm_epoch.tm_isdst = -1;
923        tm_epoch.tm_gmtoff = 0;
924        tm_epoch.tm_zone = NULL;
925        epoch = timegm(&tm_epoch);
926    }
927    return epoch;
928}
929
930size_t
931lldb_private::formatters::ExtractIndexFromString (const char* item_name)
932{
933    if (!item_name || !*item_name)
934        return UINT32_MAX;
935    if (*item_name != '[')
936        return UINT32_MAX;
937    item_name++;
938    char* endptr = NULL;
939    unsigned long int idx = ::strtoul(item_name, &endptr, 0);
940    if (idx == 0 && endptr == item_name)
941        return UINT32_MAX;
942    if (idx == ULONG_MAX)
943        return UINT32_MAX;
944    return idx;
945}
946
947lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
948                                                                                            ConstString item_name) :
949SyntheticChildrenFrontEnd(*valobj_sp.get()),
950m_exe_ctx_ref(),
951m_item_name(item_name),
952m_item_sp()
953{
954    if (valobj_sp)
955        Update();
956}
957
958bool
959lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update()
960{
961    m_item_sp.reset();
962
963    ValueObjectSP valobj_sp = m_backend.GetSP();
964    if (!valobj_sp)
965        return false;
966
967    if (!valobj_sp)
968        return false;
969
970    ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true));
971    if (!item_ptr)
972        return false;
973    if (item_ptr->GetValueAsUnsigned(0) == 0)
974        return false;
975    Error err;
976    m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
977    m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, ClangASTType(item_ptr->GetClangAST(),ClangASTType::GetPointeeType(item_ptr->GetClangType())));
978    if (err.Fail())
979        m_item_sp.reset();
980    return false;
981}
982
983size_t
984lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren ()
985{
986    return 1;
987}
988
989lldb::ValueObjectSP
990lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
991{
992    if (idx == 0)
993        return m_item_sp;
994    return lldb::ValueObjectSP();
995}
996
997bool
998lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren ()
999{
1000    return true;
1001}
1002
1003size_t
1004lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1005{
1006    if (name == ConstString("item"))
1007        return 0;
1008    return UINT32_MAX;
1009}
1010
1011lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd ()
1012{
1013}
1014
1015template bool
1016lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
1017
1018template bool
1019lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
1020
1021template bool
1022lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ;
1023
1024template bool
1025lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ;
1026