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