CXXFormatterFunctions.cpp revision 39ebb982b3f9de4a15744078e9c6ba231187b5dc
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/DataFormatters/CXXFormatterFunctions.h"
11
12#include "llvm/Support/ConvertUTF.h"
13
14#include "lldb/Core/DataBufferHeap.h"
15#include "lldb/Core/Error.h"
16#include "lldb/Core/Stream.h"
17#include "lldb/Core/ValueObject.h"
18#include "lldb/Core/ValueObjectConstResult.h"
19#include "lldb/Host/Endian.h"
20#include "lldb/Symbol/ClangASTContext.h"
21#include "lldb/Target/ObjCLanguageRuntime.h"
22#include "lldb/Target/Target.h"
23
24#include <algorithm>
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                       uint32_t 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(4*bufferSPSize,0));
220            utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
221            utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize();
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>
249class ReadUTFBufferAndDumpToStreamOptions
250{
251public:
252    typedef ConversionResult (*ConvertFunctionType) (const SourceDataType**,
253                                                     const SourceDataType*,
254                                                     UTF8**,
255                                                     UTF8*,
256                                                     ConversionFlags);
257
258    ReadUTFBufferAndDumpToStreamOptions () :
259    m_conversion_function(NULL),
260    m_location(0),
261    m_process_sp(),
262    m_stream(NULL),
263    m_prefix_token('@'),
264    m_quote('"'),
265    m_source_size(0),
266    m_needs_zero_termination(true)
267    {
268    }
269
270    ReadUTFBufferAndDumpToStreamOptions&
271    SetConversionFunction (ConvertFunctionType f)
272    {
273        m_conversion_function = f;
274        return *this;
275    }
276
277    ConvertFunctionType
278    GetConversionFunction () const
279    {
280        return m_conversion_function;
281    }
282
283    ReadUTFBufferAndDumpToStreamOptions&
284    SetLocation (uint64_t l)
285    {
286        m_location = l;
287        return *this;
288    }
289
290    uint64_t
291    GetLocation () const
292    {
293        return m_location;
294    }
295
296    ReadUTFBufferAndDumpToStreamOptions&
297    SetProcessSP (ProcessSP p)
298    {
299        m_process_sp = p;
300        return *this;
301    }
302
303    ProcessSP
304    GetProcessSP () const
305    {
306        return m_process_sp;
307    }
308
309    ReadUTFBufferAndDumpToStreamOptions&
310    SetStream (Stream* s)
311    {
312        m_stream = s;
313        return *this;
314    }
315
316    Stream*
317    GetStream () const
318    {
319        return m_stream;
320    }
321
322    ReadUTFBufferAndDumpToStreamOptions&
323    SetPrefixToken (char p)
324    {
325        m_prefix_token = p;
326        return *this;
327    }
328
329    char
330    GetPrefixToken () const
331    {
332        return m_prefix_token;
333    }
334
335    ReadUTFBufferAndDumpToStreamOptions&
336    SetQuote (char q)
337    {
338        m_quote = q;
339        return *this;
340    }
341
342    char
343    GetQuote () const
344    {
345        return m_quote;
346    }
347
348    ReadUTFBufferAndDumpToStreamOptions&
349    SetSourceSize (uint32_t s)
350    {
351        m_source_size = s;
352        return *this;
353    }
354
355    uint32_t
356    GetSourceSize () const
357    {
358        return m_source_size;
359    }
360
361    ReadUTFBufferAndDumpToStreamOptions&
362    SetNeedsZeroTermination (bool z)
363    {
364        m_needs_zero_termination = z;
365        return *this;
366    }
367
368    bool
369    GetNeedsZeroTermination () const
370    {
371        return m_needs_zero_termination;
372    }
373
374private:
375    ConvertFunctionType m_conversion_function;
376    uint64_t m_location;
377    ProcessSP m_process_sp;
378    Stream* m_stream;
379    char m_prefix_token;
380    char m_quote;
381    uint32_t m_source_size;
382    bool m_needs_zero_termination;
383};
384
385template<typename SourceDataType>
386static bool
387ReadUTFBufferAndDumpToStream (const ReadUTFBufferAndDumpToStreamOptions<SourceDataType>& options)
388{
389    if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS)
390        return false;
391
392    ProcessSP process_sp(options.GetProcessSP());
393
394    if (!process_sp)
395        return false;
396
397    const int type_width = sizeof(SourceDataType);
398    const int origin_encoding = 8 * type_width ;
399    if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
400        return false;
401    // if not UTF8, I need a conversion function to return proper UTF8
402    if (origin_encoding != 8 && !options.GetConversionFunction())
403        return false;
404
405    if (!options.GetStream())
406        return false;
407
408    uint32_t sourceSize = options.GetSourceSize();
409    bool needs_zero_terminator = options.GetNeedsZeroTermination();
410
411    if (!sourceSize)
412    {
413        sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
414        needs_zero_terminator = true;
415    }
416    else
417        sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
418
419    const int bufferSPSize = sourceSize * type_width;
420
421    lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
422
423    if (!buffer_sp->GetBytes())
424        return false;
425
426    Error error;
427    char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes());
428
429    size_t data_read = 0;
430    if (needs_zero_terminator)
431        data_read = process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width);
432    else
433        data_read = process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error);
434
435    if (error.Fail() || data_read == 0)
436    {
437        options.GetStream()->Printf("unable to read data");
438        return true;
439    }
440
441    DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
442
443    return DumpUTFBufferToStream(options.GetConversionFunction(), data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize);
444}
445
446bool
447lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream)
448{
449    ProcessSP process_sp = valobj.GetProcessSP();
450    if (!process_sp)
451        return false;
452
453    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
454
455    if (!valobj_addr)
456        return false;
457
458    ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
459    options.SetLocation(valobj_addr);
460    options.SetConversionFunction(ConvertUTF16toUTF8);
461    options.SetProcessSP(process_sp);
462    options.SetStream(&stream);
463    options.SetPrefixToken('u');
464
465    if (!ReadUTFBufferAndDumpToStream(options))
466    {
467        stream.Printf("Summary Unavailable");
468        return true;
469    }
470
471    return true;
472}
473
474bool
475lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream)
476{
477    ProcessSP process_sp = valobj.GetProcessSP();
478    if (!process_sp)
479        return false;
480
481    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
482
483    if (!valobj_addr)
484        return false;
485
486    ReadUTFBufferAndDumpToStreamOptions<UTF32> options;
487    options.SetLocation(valobj_addr);
488    options.SetConversionFunction(ConvertUTF32toUTF8);
489    options.SetProcessSP(process_sp);
490    options.SetStream(&stream);
491    options.SetPrefixToken('U');
492
493    if (!ReadUTFBufferAndDumpToStream(options))
494    {
495        stream.Printf("Summary Unavailable");
496        return true;
497    }
498
499    return true;
500}
501
502bool
503lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream)
504{
505    ProcessSP process_sp = valobj.GetProcessSP();
506    if (!process_sp)
507        return false;
508
509    lldb::addr_t data_addr = 0;
510
511    if (valobj.IsPointerType())
512        data_addr = valobj.GetValueAsUnsigned(0);
513    else if (valobj.IsArrayType())
514        data_addr = valobj.GetAddressOf();
515
516    if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS)
517        return false;
518
519    clang::ASTContext* ast = valobj.GetClangAST();
520
521    if (!ast)
522        return false;
523
524    uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
525
526    switch (wchar_size)
527    {
528        case 8:
529        {
530            // utf 8
531
532            ReadUTFBufferAndDumpToStreamOptions<UTF8> options;
533            options.SetLocation(data_addr);
534            options.SetConversionFunction(nullptr);
535            options.SetProcessSP(process_sp);
536            options.SetStream(&stream);
537            options.SetPrefixToken('L');
538
539            return ReadUTFBufferAndDumpToStream(options);
540        }
541        case 16:
542        {
543            // utf 16
544            ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
545            options.SetLocation(data_addr);
546            options.SetConversionFunction(ConvertUTF16toUTF8);
547            options.SetProcessSP(process_sp);
548            options.SetStream(&stream);
549            options.SetPrefixToken('L');
550
551            return ReadUTFBufferAndDumpToStream(options);
552        }
553        case 32:
554        {
555            // utf 32
556            ReadUTFBufferAndDumpToStreamOptions<UTF32> options;
557            options.SetLocation(data_addr);
558            options.SetConversionFunction(ConvertUTF32toUTF8);
559            options.SetProcessSP(process_sp);
560            options.SetStream(&stream);
561            options.SetPrefixToken('L');
562
563            return ReadUTFBufferAndDumpToStream(options);
564        }
565        default:
566            stream.Printf("size for wchar_t is not valid");
567            return true;
568    }
569    return true;
570}
571
572bool
573lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
574{
575    DataExtractor data;
576    valobj.GetData(data);
577
578    std::string value;
579    valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
580    if (!value.empty())
581        stream.Printf("%s ", value.c_str());
582
583    return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1);
584}
585
586bool
587lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
588{
589    DataExtractor data;
590    valobj.GetData(data);
591
592    std::string value;
593    valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
594    if (!value.empty())
595        stream.Printf("%s ", value.c_str());
596
597    return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1);
598}
599
600bool
601lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
602{
603    DataExtractor data;
604    valobj.GetData(data);
605
606    clang::ASTContext* ast = valobj.GetClangAST();
607
608    if (!ast)
609        return false;
610
611    std::string value;
612
613    uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
614
615    switch (wchar_size)
616    {
617        case 8:
618            // utf 8
619            valobj.GetValueAsCString(lldb::eFormatChar, value);
620            if (!value.empty())
621                stream.Printf("%s ", value.c_str());
622            return DumpUTFBufferToStream<UTF8>(nullptr,
623                                               data,
624                                               stream,
625                                               'L',
626                                               '\'',
627                                               1);
628        case 16:
629            // utf 16
630            valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
631            if (!value.empty())
632                stream.Printf("%s ", value.c_str());
633            return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,
634                                                data,
635                                                stream,
636                                                'L',
637                                                '\'',
638                                                1);
639        case 32:
640            // utf 32
641            valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
642            if (!value.empty())
643                stream.Printf("%s ", value.c_str());
644            return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,
645                                                data,
646                                                stream,
647                                                'L',
648                                                '\'',
649                                                1);
650        default:
651            stream.Printf("size for wchar_t is not valid");
652            return true;
653    }
654    return true;
655}
656
657// this function extracts information from a libcxx std::basic_string<>
658// irregardless of template arguments. it reports the size (in item count not bytes)
659// and the location in memory where the string data can be found
660static bool
661ExtractLibcxxStringInfo (ValueObject& valobj,
662                         ValueObjectSP &location_sp,
663                         uint64_t& size)
664{
665    ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
666    if (!D)
667        return false;
668
669    ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
670    if (!size_mode)
671        return false;
672
673    uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0));
674
675    if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline
676    {
677        ValueObjectSP s(D->GetChildAtIndex(1, true));
678        if (!s)
679            return false;
680        size = ((size_mode_value >> 1) % 256);
681        location_sp = s->GetChildAtIndex(1, true);
682        return (location_sp.get() != nullptr);
683    }
684    else
685    {
686        ValueObjectSP l(D->GetChildAtIndex(0, true));
687        if (!l)
688            return false;
689        location_sp = l->GetChildAtIndex(2, true);
690        ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
691        if (!size_vo || !location_sp)
692            return false;
693        size = size_vo->GetValueAsUnsigned(0);
694        return true;
695    }
696}
697
698bool
699lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
700{
701    uint64_t size = 0;
702    ValueObjectSP location_sp((ValueObject*)nullptr);
703    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
704        return false;
705    if (size == 0)
706    {
707        stream.Printf("L\"\"");
708        return true;
709    }
710    if (!location_sp)
711        return false;
712    return WCharStringSummaryProvider(*location_sp.get(), stream);
713}
714
715bool
716lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
717{
718    uint64_t size = 0;
719    ValueObjectSP location_sp((ValueObject*)nullptr);
720    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
721        return false;
722    if (size == 0)
723    {
724        stream.Printf("\"\"");
725        return true;
726    }
727    if (!location_sp)
728        return false;
729    Error error;
730    if (location_sp->ReadPointedString(stream,
731                                       error,
732                                       0, // max length is decided by the settings
733                                       false) == 0) // do not honor array (terminates on first 0 byte even for a char[])
734        stream.Printf("\"\""); // if nothing was read, print an empty string
735    return error.Success();
736}
737
738bool
739lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream)
740{
741    ProcessSP process_sp = valobj.GetProcessSP();
742    if (!process_sp)
743        return false;
744
745    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
746
747    if (!runtime)
748        return false;
749
750    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
751
752    if (!descriptor.get() || !descriptor->IsValid())
753        return false;
754
755    const char* class_name = descriptor->GetClassName().GetCString();
756
757    if (!class_name || !*class_name)
758        return false;
759
760    stream.Printf("%s",class_name);
761    return true;
762}
763
764class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd
765{
766public:
767    ObjCClassSyntheticChildrenFrontEnd (lldb::ValueObjectSP valobj_sp) :
768    SyntheticChildrenFrontEnd(*valobj_sp.get())
769    {
770    }
771
772    virtual size_t
773    CalculateNumChildren ()
774    {
775        return 0;
776    }
777
778    virtual lldb::ValueObjectSP
779    GetChildAtIndex (size_t idx)
780    {
781        return lldb::ValueObjectSP();
782    }
783
784    virtual bool
785    Update()
786    {
787        return false;
788    }
789
790    virtual bool
791    MightHaveChildren ()
792    {
793        return false;
794    }
795
796    virtual size_t
797    GetIndexOfChildWithName (const ConstString &name)
798    {
799        return UINT32_MAX;
800    }
801
802    virtual
803    ~ObjCClassSyntheticChildrenFrontEnd ()
804    {
805    }
806};
807
808SyntheticChildrenFrontEnd*
809lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
810{
811    return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
812}
813
814template<bool needs_at>
815bool
816lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream)
817{
818    ProcessSP process_sp = valobj.GetProcessSP();
819    if (!process_sp)
820        return false;
821
822    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
823
824    if (!runtime)
825        return false;
826
827    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
828
829    if (!descriptor.get() || !descriptor->IsValid())
830        return false;
831
832    bool is_64bit = (process_sp->GetAddressByteSize() == 8);
833    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
834
835    if (!valobj_addr)
836        return false;
837
838    uint64_t value = 0;
839
840    const char* class_name = descriptor->GetClassName().GetCString();
841
842    if (!class_name || !*class_name)
843        return false;
844
845    if (!strcmp(class_name,"NSConcreteData") ||
846        !strcmp(class_name,"NSConcreteMutableData") ||
847        !strcmp(class_name,"__NSCFData"))
848    {
849        uint32_t offset = (is_64bit ? 16 : 8);
850        Error error;
851        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
852        if (error.Fail())
853            return false;
854    }
855    else
856    {
857        if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
858            return false;
859    }
860
861    stream.Printf("%s%" PRIu64 " byte%s%s",
862                  (needs_at ? "@\"" : ""),
863                  value,
864                  (value > 1 ? "s" : ""),
865                  (needs_at ? "\"" : ""));
866
867    return true;
868}
869
870static bool
871ReadAsciiBufferAndDumpToStream (lldb::addr_t location,
872                                lldb::ProcessSP& process_sp,
873                                Stream& dest,
874                                uint32_t size = 0,
875                                Error* error = NULL,
876                                size_t *data_read = NULL,
877                                char prefix_token = '@',
878                                char quote = '"')
879{
880    Error my_error;
881    size_t my_data_read;
882    if (!process_sp || location == 0)
883        return false;
884
885    if (!size)
886        size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
887    else
888        size = std::min(size,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
889
890    lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
891
892    my_data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), size, my_error);
893
894    if (error)
895        *error = my_error;
896    if (data_read)
897        *data_read = my_data_read;
898
899    if (my_error.Fail())
900        return false;
901    if (my_data_read)
902        dest.Printf("%c%c%s%c",prefix_token,quote,(char*)buffer_sp->GetBytes(),quote);
903
904    return true;
905}
906
907#ifdef WANT_DEEP_PRINT
908struct lldb__notInlineMutable {
909    void *buffer;
910    signed long length;
911    signed long capacity;
912    unsigned int hasGap:1;
913    unsigned int isFixedCapacity:1;
914    unsigned int isExternalMutable:1;
915    unsigned int capacityProvidedExternally:1;
916#if __LP64__
917    unsigned long desiredCapacity:60;
918#else
919    unsigned long desiredCapacity:28;
920#endif
921    void* contentsAllocator;
922};
923
924struct lldb__CFString {
925    uintptr_t _cfisa;
926    uint8_t _cfinfo[4];
927    uint32_t _rc;
928    union {
929        struct __inline1 {
930            signed long length;
931        } inline1;
932        struct __notInlineImmutable1 {
933            void *buffer;
934            signed long length;
935            void* contentsDeallocator;
936        } notInlineImmutable1;
937        struct __notInlineImmutable2 {
938            void *buffer;
939            void* contentsDeallocator;
940        } notInlineImmutable2;
941        struct lldb__notInlineMutable notInlineMutable;
942    } variants;
943};
944#endif
945
946bool
947lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
948{
949    ProcessSP process_sp = valobj.GetProcessSP();
950    if (!process_sp)
951        return false;
952
953    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
954
955    if (!runtime)
956        return false;
957
958    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
959
960    if (!descriptor.get() || !descriptor->IsValid())
961        return false;
962
963    uint32_t ptr_size = process_sp->GetAddressByteSize();
964
965    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
966
967    if (!valobj_addr)
968        return false;
969
970    const char* class_name = descriptor->GetClassName().GetCString();
971
972    if (!class_name || !*class_name)
973        return false;
974
975    uint64_t info_bits_location = valobj_addr + ptr_size;
976    if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
977        info_bits_location += 3;
978
979    Error error;
980
981    uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error);
982    if (error.Fail())
983        return false;
984
985    bool is_mutable = (info_bits & 1) == 1;
986    bool is_inline = (info_bits & 0x60) == 0;
987    bool has_explicit_length = (info_bits & (1 | 4)) != 4;
988    bool is_unicode = (info_bits & 0x10) == 0x10;
989    bool is_special = strcmp(class_name,"NSPathStore2") == 0;
990    bool has_null = (info_bits & 8) == 8;
991
992    size_t explicit_length = 0;
993    if (!has_null && has_explicit_length && !is_special)
994    {
995        lldb::addr_t explicit_length_offset = 2*ptr_size;
996        if (is_mutable and not is_inline)
997            explicit_length_offset = explicit_length_offset + ptr_size; //  notInlineMutable.length;
998        else if (is_inline)
999            explicit_length = explicit_length + 0; // inline1.length;
1000        else if (not is_inline and not is_mutable)
1001            explicit_length_offset = explicit_length_offset + ptr_size; // notInlineImmutable1.length;
1002        else
1003            explicit_length_offset = 0;
1004
1005        if (explicit_length_offset)
1006        {
1007            explicit_length_offset = valobj_addr + explicit_length_offset;
1008            explicit_length = process_sp->ReadUnsignedIntegerFromMemory(explicit_length_offset, 4, 0, error);
1009        }
1010    }
1011
1012#ifdef WANT_DEEP_PRINT
1013    lldb__CFString my_string_data;
1014    process_sp->ReadMemory(valobj_addr, &my_string_data, sizeof(lldb__CFString),error);
1015
1016    printf(R"(
1017           __CFString my_string_data = {
1018           uintptr_t _cfisa = %lu
1019           uint8_t _cfinfo[4] = %c%c%c%c
1020           uint32_t _rc = %d
1021           union {
1022               struct __inline1 {
1023                   signed long length = %ld
1024               } inline1;
1025               struct __notInlineImmutable1 {
1026                   void *buffer = %p
1027                   signed long length = %ld
1028                   void* contentsDeallocator = %p
1029               } notInlineImmutable1;
1030               struct __notInlineImmutable2 {
1031                   void *buffer = %p
1032                   void* contentsDeallocator = %p
1033               } notInlineImmutable2;
1034               struct __notInlineMutable notInlineMutable {
1035                   void *buffer = %p
1036                   signed long length = %ld
1037                   signed long capacity = %ld
1038                   unsigned int hasGap:1 = %d
1039                   unsigned int isFixedCapacity:1 = %d
1040                   unsigned int isExternalMutable:1 = %d
1041                   unsigned int capacityProvidedExternally:1 = %d
1042#if __LP64__
1043                   unsigned long desiredCapacity:60 = %lu
1044#else
1045                   unsigned long desiredCapacity:28 = %lu
1046#endif
1047                   void* contentsAllocator = %p
1048               }
1049           } variants; ==> (M:%dI:%dL:%zuU:%dS:%dN:%d)
1050           };\n)",
1051    my_string_data._cfisa,
1052    my_string_data._cfinfo[0],my_string_data._cfinfo[1],my_string_data._cfinfo[2],my_string_data._cfinfo[3],
1053    my_string_data._rc,
1054    my_string_data.variants.inline1.length,
1055    my_string_data.variants.notInlineImmutable1.buffer,
1056    my_string_data.variants.notInlineImmutable1.length,
1057    my_string_data.variants.notInlineImmutable1.contentsDeallocator,
1058    my_string_data.variants.notInlineImmutable2.buffer,
1059    my_string_data.variants.notInlineImmutable2.contentsDeallocator,
1060    my_string_data.variants.notInlineMutable.buffer,
1061    my_string_data.variants.notInlineMutable.length,
1062    my_string_data.variants.notInlineMutable.capacity,
1063    my_string_data.variants.notInlineMutable.hasGap,
1064    my_string_data.variants.notInlineMutable.isFixedCapacity,
1065    my_string_data.variants.notInlineMutable.isExternalMutable,
1066    my_string_data.variants.notInlineMutable.capacityProvidedExternally,
1067    my_string_data.variants.notInlineMutable.desiredCapacity,
1068    my_string_data.variants.notInlineMutable.desiredCapacity,
1069    my_string_data.variants.notInlineMutable.contentsAllocator,
1070    is_mutable,
1071    is_inline,
1072    explicit_length,
1073    is_unicode,
1074    is_special,
1075    has_null);
1076#endif
1077
1078    if (strcmp(class_name,"NSString") &&
1079        strcmp(class_name,"CFStringRef") &&
1080        strcmp(class_name,"CFMutableStringRef") &&
1081        strcmp(class_name,"__NSCFConstantString") &&
1082        strcmp(class_name,"__NSCFString") &&
1083        strcmp(class_name,"NSCFConstantString") &&
1084        strcmp(class_name,"NSCFString") &&
1085        strcmp(class_name,"NSPathStore2"))
1086    {
1087        // not one of us - but tell me class name
1088        stream.Printf("class name = %s",class_name);
1089        return true;
1090    }
1091
1092    if (is_mutable)
1093    {
1094        uint64_t location = 2 * ptr_size + valobj_addr;
1095        location = process_sp->ReadPointerFromMemory(location, error);
1096        if (error.Fail())
1097            return false;
1098        if (has_explicit_length and is_unicode)
1099        {
1100            ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
1101            options.SetConversionFunction(ConvertUTF16toUTF8);
1102            options.SetLocation(location);
1103            options.SetProcessSP(process_sp);
1104            options.SetStream(&stream);
1105            options.SetPrefixToken('@');
1106            options.SetQuote('"');
1107            options.SetSourceSize(explicit_length);
1108            options.SetNeedsZeroTermination(false);
1109            return ReadUTFBufferAndDumpToStream (options);
1110        }
1111        else
1112            return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream, explicit_length);
1113    }
1114    else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable)
1115    {
1116        uint64_t location = 3 * ptr_size + valobj_addr;
1117        return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length);
1118    }
1119    else if (is_unicode)
1120    {
1121        uint64_t location = valobj_addr + 2*ptr_size;
1122        if (is_inline)
1123        {
1124            if (!has_explicit_length)
1125            {
1126                stream.Printf("found new combo");
1127                return true;
1128            }
1129            else
1130                location += ptr_size;
1131        }
1132        else
1133        {
1134            location = process_sp->ReadPointerFromMemory(location, error);
1135            if (error.Fail())
1136                return false;
1137        }
1138        ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
1139        options.SetConversionFunction(ConvertUTF16toUTF8);
1140        options.SetLocation(location);
1141        options.SetProcessSP(process_sp);
1142        options.SetStream(&stream);
1143        options.SetPrefixToken('@');
1144        options.SetQuote('"');
1145        options.SetSourceSize(explicit_length);
1146        options.SetNeedsZeroTermination(has_explicit_length == false);
1147        return ReadUTFBufferAndDumpToStream (options);
1148    }
1149    else if (is_special)
1150    {
1151        uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8);
1152        ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
1153        options.SetConversionFunction(ConvertUTF16toUTF8);
1154        options.SetLocation(location);
1155        options.SetProcessSP(process_sp);
1156        options.SetStream(&stream);
1157        options.SetPrefixToken('@');
1158        options.SetQuote('"');
1159        options.SetSourceSize(explicit_length);
1160        options.SetNeedsZeroTermination(has_explicit_length == false);
1161        return ReadUTFBufferAndDumpToStream (options);
1162    }
1163    else if (is_inline)
1164    {
1165        uint64_t location = valobj_addr + 2*ptr_size;
1166        if (!has_explicit_length)
1167            location++;
1168        return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length);
1169    }
1170    else
1171    {
1172        uint64_t location = valobj_addr + 2*ptr_size;
1173        location = process_sp->ReadPointerFromMemory(location, error);
1174        if (error.Fail())
1175            return false;
1176        return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length);
1177    }
1178
1179    stream.Printf("class name = %s",class_name);
1180    return true;
1181
1182}
1183
1184bool
1185lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1186{
1187    TargetSP target_sp(valobj.GetTargetSP());
1188    if (!target_sp)
1189        return false;
1190    uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
1191    uint64_t pointee = valobj.GetValueAsUnsigned(0);
1192    if (!pointee)
1193        return false;
1194    pointee += addr_size;
1195    ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
1196    ExecutionContext exe_ctx(target_sp,false);
1197    ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointee, exe_ctx, type));
1198    if (!child_ptr_sp)
1199        return false;
1200    DataExtractor data;
1201    child_ptr_sp->GetData(data);
1202    ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type));
1203    child_sp->GetValueAsUnsigned(0);
1204    if (child_sp)
1205        return NSStringSummaryProvider(*child_sp, stream);
1206    return false;
1207}
1208
1209bool
1210lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1211{
1212    return NSAttributedStringSummaryProvider(valobj, stream);
1213}
1214
1215bool
1216lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream)
1217{
1218    stream.Printf("%s",valobj.GetObjectDescription());
1219    return true;
1220}
1221
1222bool
1223lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream)
1224{
1225    const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(),
1226                                                            valobj.GetClangAST(),
1227                                                            NULL);
1228
1229    ValueObjectSP real_guy_sp = valobj.GetSP();
1230
1231    if (type_info & ClangASTContext::eTypeIsPointer)
1232    {
1233        Error err;
1234        real_guy_sp = valobj.Dereference(err);
1235        if (err.Fail() || !real_guy_sp)
1236            return false;
1237    }
1238    else if (type_info & ClangASTContext::eTypeIsReference)
1239    {
1240        real_guy_sp =  valobj.GetChildAtIndex(0, true);
1241        if (!real_guy_sp)
1242            return false;
1243    }
1244    uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
1245    if (value == 0)
1246    {
1247        stream.Printf("NO");
1248        return true;
1249    }
1250    stream.Printf("YES");
1251    return true;
1252}
1253
1254template <bool is_sel_ptr>
1255bool
1256lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream)
1257{
1258    lldb::ValueObjectSP valobj_sp;
1259
1260    if (!valobj.GetClangAST())
1261        return false;
1262    void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr();
1263    if (!char_opaque_type)
1264        return false;
1265    ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type));
1266
1267    ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1268
1269    if (is_sel_ptr)
1270    {
1271        lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1272        if (data_address == LLDB_INVALID_ADDRESS)
1273            return false;
1274        valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar);
1275    }
1276    else
1277    {
1278        DataExtractor data;
1279        valobj.GetData(data);
1280        valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
1281    }
1282
1283    if (!valobj_sp)
1284        return false;
1285
1286    stream.Printf("%s",valobj_sp->GetSummaryAsCString());
1287    return true;
1288}
1289
1290// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
1291// this call gives the POSIX equivalent of the Cocoa epoch
1292time_t
1293lldb_private::formatters::GetOSXEpoch ()
1294{
1295    static time_t epoch = 0;
1296    if (!epoch)
1297    {
1298        tzset();
1299        tm tm_epoch;
1300        tm_epoch.tm_sec = 0;
1301        tm_epoch.tm_hour = 0;
1302        tm_epoch.tm_min = 0;
1303        tm_epoch.tm_mon = 0;
1304        tm_epoch.tm_mday = 1;
1305        tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why.
1306        tm_epoch.tm_isdst = -1;
1307        tm_epoch.tm_gmtoff = 0;
1308        tm_epoch.tm_zone = NULL;
1309        epoch = timegm(&tm_epoch);
1310    }
1311    return epoch;
1312}
1313
1314size_t
1315lldb_private::formatters::ExtractIndexFromString (const char* item_name)
1316{
1317    if (!item_name || !*item_name)
1318        return UINT32_MAX;
1319    if (*item_name != '[')
1320        return UINT32_MAX;
1321    item_name++;
1322    char* endptr = NULL;
1323    unsigned long int idx = ::strtoul(item_name, &endptr, 0);
1324    if (idx == 0 && endptr == item_name)
1325        return UINT32_MAX;
1326    if (idx == ULONG_MAX)
1327        return UINT32_MAX;
1328    return idx;
1329}
1330
1331lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
1332                                                                                            ConstString item_name) :
1333SyntheticChildrenFrontEnd(*valobj_sp.get()),
1334m_exe_ctx_ref(),
1335m_item_name(item_name),
1336m_item_sp()
1337{
1338    if (valobj_sp)
1339        Update();
1340}
1341
1342bool
1343lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update()
1344{
1345    m_item_sp.reset();
1346
1347    ValueObjectSP valobj_sp = m_backend.GetSP();
1348    if (!valobj_sp)
1349        return false;
1350
1351    if (!valobj_sp)
1352        return false;
1353
1354    ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true));
1355    if (!item_ptr)
1356        return false;
1357    if (item_ptr->GetValueAsUnsigned(0) == 0)
1358        return false;
1359    Error err;
1360    m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1361    m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, ClangASTType(item_ptr->GetClangAST(),ClangASTType::GetPointeeType(item_ptr->GetClangType())));
1362    if (err.Fail())
1363        m_item_sp.reset();
1364    return false;
1365}
1366
1367size_t
1368lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren ()
1369{
1370    return 1;
1371}
1372
1373lldb::ValueObjectSP
1374lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1375{
1376    if (idx == 0)
1377        return m_item_sp;
1378    return lldb::ValueObjectSP();
1379}
1380
1381bool
1382lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren ()
1383{
1384    return true;
1385}
1386
1387size_t
1388lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1389{
1390    if (name == ConstString("item"))
1391        return 0;
1392    return UINT32_MAX;
1393}
1394
1395lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd ()
1396{
1397}
1398
1399template bool
1400lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
1401
1402template bool
1403lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
1404
1405template bool
1406lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ;
1407
1408template bool
1409lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ;
1410