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