CXXFormatterFunctions.cpp revision dcffc1a667665936b3dd33a9861a3de9d1d35636
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
64lldb::ValueObjectSP
65lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
66                                                const char* return_type,
67                                                const char* selector,
68                                                uint64_t index)
69{
70    lldb::ValueObjectSP valobj_sp;
71    if (!return_type || !*return_type)
72        return valobj_sp;
73    if (!selector || !*selector)
74        return valobj_sp;
75    StreamString expr_path_stream;
76    valobj.GetExpressionPath(expr_path_stream, false);
77    StreamString expr;
78    expr.Printf("(%s)[%s %s:%" PRId64 "]",return_type,expr_path_stream.GetData(),selector,index);
79    ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
80    lldb::ValueObjectSP result_sp;
81    Target* target = exe_ctx.GetTargetPtr();
82    StackFrame* stack_frame = exe_ctx.GetFramePtr();
83    if (!target || !stack_frame)
84        return valobj_sp;
85
86    EvaluateExpressionOptions options;
87    options.SetCoerceToId(false)
88    .SetUnwindOnError(true)
89    .SetKeepInMemory(true)
90    .SetUseDynamic(lldb::eDynamicCanRunTarget);
91
92    target->EvaluateExpression(expr.GetData(),
93                               stack_frame,
94                               valobj_sp,
95                               options);
96    return valobj_sp;
97}
98
99lldb::ValueObjectSP
100lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
101                                                const char* return_type,
102                                                const char* selector,
103                                                const char* key)
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    if (!key || !*key)
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:%s]",return_type,expr_path_stream.GetData(),selector,key);
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
136// use this call if you already have an LLDB-side buffer for the data
137template<typename SourceDataType>
138static bool
139DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
140                                                            const SourceDataType*,
141                                                            UTF8**,
142                                                            UTF8*,
143                                                            ConversionFlags),
144                       DataExtractor& data,
145                       Stream& stream,
146                       char prefix_token = '@',
147                       char quote = '"',
148                       int sourceSize = 0)
149{
150    if (prefix_token != 0)
151        stream.Printf("%c",prefix_token);
152    if (quote != 0)
153        stream.Printf("%c",quote);
154    if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
155    {
156        const int bufferSPSize = data.GetByteSize();
157        if (sourceSize == 0)
158        {
159            const int origin_encoding = 8*sizeof(SourceDataType);
160            sourceSize = bufferSPSize/(origin_encoding >> 2);
161        }
162
163        SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart();
164        SourceDataType *data_end_ptr = data_ptr + sourceSize;
165
166        while (data_ptr < data_end_ptr)
167        {
168            if (!*data_ptr)
169            {
170                data_end_ptr = data_ptr;
171                break;
172            }
173            data_ptr++;
174        }
175
176        *data_ptr = 0;
177        data_ptr = (SourceDataType*)data.GetDataStart();
178
179        lldb::DataBufferSP utf8_data_buffer_sp;
180        UTF8* utf8_data_ptr = nullptr;
181        UTF8* utf8_data_end_ptr = nullptr;
182
183        if (ConvertFunction)
184        {
185            utf8_data_buffer_sp.reset(new DataBufferHeap(bufferSPSize,0));
186            utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
187            utf8_data_end_ptr = utf8_data_ptr + bufferSPSize;
188            ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
189            utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
190        }
191        else
192        {
193            // just copy the pointers - the cast is necessary to make the compiler happy
194            // but this should only happen if we are reading UTF8 data
195            utf8_data_ptr = (UTF8*)data_ptr;
196            utf8_data_end_ptr = (UTF8*)data_end_ptr;
197        }
198
199        // since we tend to accept partial data (and even partially malformed data)
200        // we might end up with no NULL terminator before the end_ptr
201        // hence we need to take a slower route and ensure we stay within boundaries
202        for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++)
203        {
204            if (!*utf8_data_ptr)
205                break;
206            stream.Printf("%c",*utf8_data_ptr);
207        }
208    }
209    if (quote != 0)
210        stream.Printf("%c",quote);
211    return true;
212}
213
214template<typename SourceDataType>
215static bool
216ReadUTFBufferAndDumpToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
217                                                                   const SourceDataType*,
218                                                                   UTF8**,
219                                                                   UTF8*,
220                                                                   ConversionFlags),
221                              uint64_t location,
222                              const ProcessSP& process_sp,
223                              Stream& stream,
224                              char prefix_token = '@',
225                              char quote = '"',
226                              int sourceSize = 0)
227{
228    if (location == 0 || location == LLDB_INVALID_ADDRESS)
229        return false;
230    if (!process_sp)
231        return false;
232
233    const int origin_encoding = 8*sizeof(SourceDataType);
234    if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
235        return false;
236    // if not UTF8, I need a conversion function to return proper UTF8
237    if (origin_encoding != 8 && !ConvertFunction)
238        return false;
239
240    if (sourceSize == 0)
241        sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
242    const int bufferSPSize = sourceSize * (origin_encoding >> 2);
243
244    Error error;
245    lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
246
247    if (!buffer_sp->GetBytes())
248        return false;
249
250    size_t data_read = process_sp->ReadMemoryFromInferior(location, (char*)buffer_sp->GetBytes(), bufferSPSize, error);
251    if (error.Fail() || data_read == 0)
252    {
253        stream.Printf("unable to read data");
254        return true;
255    }
256
257    DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
258
259    return DumpUTFBufferToStream(ConvertFunction, data, stream, prefix_token, quote, sourceSize);
260}
261
262bool
263lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream)
264{
265    ProcessSP process_sp = valobj.GetProcessSP();
266    if (!process_sp)
267        return false;
268
269    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
270
271    if (!valobj_addr)
272        return false;
273
274    if (!ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8,valobj_addr,
275                                                                 process_sp,
276                                                                 stream,
277                                                                 'u'))
278    {
279        stream.Printf("Summary Unavailable");
280        return true;
281    }
282
283    return true;
284}
285
286bool
287lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream)
288{
289    ProcessSP process_sp = valobj.GetProcessSP();
290    if (!process_sp)
291        return false;
292
293    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
294
295    if (!valobj_addr)
296        return false;
297
298    if (!ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8,valobj_addr,
299                                                                 process_sp,
300                                                                 stream,
301                                                                 'U'))
302    {
303        stream.Printf("Summary Unavailable");
304        return true;
305    }
306
307    return true;
308}
309
310bool
311lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream)
312{
313    ProcessSP process_sp = valobj.GetProcessSP();
314    if (!process_sp)
315        return false;
316
317    lldb::addr_t data_addr = 0;
318
319    if (valobj.IsPointerType())
320        data_addr = valobj.GetValueAsUnsigned(0);
321    else if (valobj.IsArrayType())
322        data_addr = valobj.GetAddressOf();
323
324    if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS)
325        return false;
326
327    clang::ASTContext* ast = valobj.GetClangAST();
328
329    if (!ast)
330        return false;
331
332    uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
333
334    switch (wchar_size)
335    {
336        case 8:
337            // utf 8
338            return ReadUTFBufferAndDumpToStream<UTF8>(nullptr, data_addr,
339                                                               process_sp,
340                                                               stream,
341                                                               'L');
342        case 16:
343            // utf 16
344            return ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8, data_addr,
345                                                                           process_sp,
346                                                                           stream,
347                                                                           'L');
348        case 32:
349            // utf 32
350            return ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8, data_addr,
351                                                                           process_sp,
352                                                                           stream,
353                                                                           'L');
354        default:
355            stream.Printf("size for wchar_t is not valid");
356            return true;
357    }
358    return true;
359}
360
361bool
362lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
363{
364    DataExtractor data;
365    valobj.GetData(data);
366
367    std::string value;
368    valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
369    if (!value.empty())
370        stream.Printf("%s ", value.c_str());
371
372    return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1);
373}
374
375bool
376lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
377{
378    DataExtractor data;
379    valobj.GetData(data);
380
381    std::string value;
382    valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
383    if (!value.empty())
384        stream.Printf("%s ", value.c_str());
385
386    return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1);
387}
388
389bool
390lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
391{
392    DataExtractor data;
393    valobj.GetData(data);
394
395    clang::ASTContext* ast = valobj.GetClangAST();
396
397    if (!ast)
398        return false;
399
400    std::string value;
401
402    uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType());
403
404    switch (wchar_size)
405    {
406        case 8:
407            // utf 8
408            valobj.GetValueAsCString(lldb::eFormatChar, value);
409            if (!value.empty())
410                stream.Printf("%s ", value.c_str());
411            return DumpUTFBufferToStream<UTF8>(nullptr,
412                                               data,
413                                               stream,
414                                               'L',
415                                               '\'',
416                                               1);
417        case 16:
418            // utf 16
419            valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
420            if (!value.empty())
421                stream.Printf("%s ", value.c_str());
422            return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,
423                                                data,
424                                                stream,
425                                                'L',
426                                                '\'',
427                                                1);
428        case 32:
429            // utf 32
430            valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
431            if (!value.empty())
432                stream.Printf("%s ", value.c_str());
433            return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,
434                                                data,
435                                                stream,
436                                                'L',
437                                                '\'',
438                                                1);
439        default:
440            stream.Printf("size for wchar_t is not valid");
441            return true;
442    }
443    return true;
444}
445
446// this function extracts information from a libcxx std::basic_string<>
447// irregardless of template arguments. it reports the size (in item count not bytes)
448// and the location in memory where the string data can be found
449static bool
450ExtractLibcxxStringInfo (ValueObject& valobj,
451                         ValueObjectSP &location_sp,
452                         uint64_t& size)
453{
454    ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
455    if (!D)
456        return false;
457
458    ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
459    if (!size_mode)
460        return false;
461
462    uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0));
463
464    if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline
465    {
466        ValueObjectSP s(D->GetChildAtIndex(1, true));
467        if (!s)
468            return false;
469        size = ((size_mode_value >> 1) % 256);
470        location_sp = s->GetChildAtIndex(1, true);
471        return (location_sp.get() != nullptr);
472    }
473    else
474    {
475        ValueObjectSP l(D->GetChildAtIndex(0, true));
476        if (!l)
477            return false;
478        location_sp = l->GetChildAtIndex(2, true);
479        ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
480        if (!size_vo || !location_sp)
481            return false;
482        size = size_vo->GetValueAsUnsigned(0);
483        return true;
484    }
485}
486
487bool
488lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
489{
490    uint64_t size = 0;
491    ValueObjectSP location_sp((ValueObject*)nullptr);
492    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
493        return false;
494    if (size == 0)
495    {
496        stream.Printf("L\"\"");
497        return true;
498    }
499    if (!location_sp)
500        return false;
501    return WCharStringSummaryProvider(*location_sp.get(), stream);
502}
503
504bool
505lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
506{
507    uint64_t size = 0;
508    ValueObjectSP location_sp((ValueObject*)nullptr);
509    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
510        return false;
511    if (size == 0)
512    {
513        stream.Printf("\"\"");
514        return true;
515    }
516    if (!location_sp)
517        return false;
518    Error error;
519    location_sp->ReadPointedString(stream,
520                                   error,
521                                   0, // max length is decided by the settings
522                                   false); // do not honor array (terminates on first 0 byte even for a char[])
523    return error.Success();
524}
525
526template<bool name_entries>
527bool
528lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream)
529{
530    ProcessSP process_sp = valobj.GetProcessSP();
531    if (!process_sp)
532        return false;
533
534    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
535
536    if (!runtime)
537        return false;
538
539    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
540
541    if (!descriptor.get() || !descriptor->IsValid())
542        return false;
543
544    uint32_t ptr_size = process_sp->GetAddressByteSize();
545    bool is_64bit = (ptr_size == 8);
546
547    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
548
549    if (!valobj_addr)
550        return false;
551
552    uint64_t value = 0;
553
554    const char* class_name = descriptor->GetClassName().GetCString();
555
556    if (!class_name || !*class_name)
557        return false;
558
559    if (!strcmp(class_name,"__NSDictionaryI"))
560    {
561        Error error;
562        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
563        if (error.Fail())
564            return false;
565        value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
566    }
567    else if (!strcmp(class_name,"__NSDictionaryM"))
568    {
569        Error error;
570        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
571        if (error.Fail())
572            return false;
573        value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
574    }
575    else if (!strcmp(class_name,"__NSCFDictionary"))
576    {
577        Error error;
578        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), ptr_size, 0, error);
579        if (error.Fail())
580            return false;
581        if (is_64bit)
582            value &= ~0x0f1f000000000000UL;
583    }
584    else
585    {
586        if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
587            return false;
588    }
589
590    stream.Printf("%s%" PRIu64 " %s%s",
591                  (name_entries ? "@\"" : ""),
592                  value,
593                  (name_entries ? (value == 1 ? "entry" : "entries") : (value == 1 ? "key/value pair" : "key/value pairs")),
594                  (name_entries ? "\"" : ""));
595    return true;
596}
597
598bool
599lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream)
600{
601    ProcessSP process_sp = valobj.GetProcessSP();
602    if (!process_sp)
603        return false;
604
605    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
606
607    if (!runtime)
608        return false;
609
610    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
611
612    if (!descriptor.get() || !descriptor->IsValid())
613        return false;
614
615    uint32_t ptr_size = process_sp->GetAddressByteSize();
616
617    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
618
619    if (!valobj_addr)
620        return false;
621
622    uint64_t value = 0;
623
624    const char* class_name = descriptor->GetClassName().GetCString();
625
626    if (!class_name || !*class_name)
627        return false;
628
629    if (!strcmp(class_name,"__NSArrayI"))
630    {
631        Error error;
632        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
633        if (error.Fail())
634            return false;
635    }
636    else if (!strcmp(class_name,"__NSArrayM"))
637    {
638        Error error;
639        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
640        if (error.Fail())
641            return false;
642    }
643    else if (!strcmp(class_name,"__NSCFArray"))
644    {
645        Error error;
646        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error);
647        if (error.Fail())
648            return false;
649    }
650    else
651    {
652        if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
653            return false;
654    }
655
656    stream.Printf("@\"%" PRIu64 " object%s\"",
657                  value,
658                  value == 1 ? "" : "s");
659    return true;
660}
661
662template<bool needs_at>
663bool
664lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream)
665{
666    ProcessSP process_sp = valobj.GetProcessSP();
667    if (!process_sp)
668        return false;
669
670    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
671
672    if (!runtime)
673        return false;
674
675    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
676
677    if (!descriptor.get() || !descriptor->IsValid())
678        return false;
679
680    bool is_64bit = (process_sp->GetAddressByteSize() == 8);
681    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
682
683    if (!valobj_addr)
684        return false;
685
686    uint64_t value = 0;
687
688    const char* class_name = descriptor->GetClassName().GetCString();
689
690    if (!class_name || !*class_name)
691        return false;
692
693    if (!strcmp(class_name,"NSConcreteData") ||
694        !strcmp(class_name,"NSConcreteMutableData") ||
695        !strcmp(class_name,"__NSCFData"))
696    {
697        uint32_t offset = (is_64bit ? 16 : 8);
698        Error error;
699        value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
700        if (error.Fail())
701            return false;
702    }
703    else
704    {
705        if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
706            return false;
707    }
708
709    stream.Printf("%s%" PRIu64 " byte%s%s",
710                  (needs_at ? "@\"" : ""),
711                  value,
712                  (value > 1 ? "s" : ""),
713                  (needs_at ? "\"" : ""));
714
715    return true;
716}
717
718bool
719lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream)
720{
721    ProcessSP process_sp = valobj.GetProcessSP();
722    if (!process_sp)
723        return false;
724
725    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
726
727    if (!runtime)
728        return false;
729
730    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
731
732    if (!descriptor.get() || !descriptor->IsValid())
733        return false;
734
735    uint32_t ptr_size = process_sp->GetAddressByteSize();
736
737    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
738
739    if (!valobj_addr)
740        return false;
741
742    const char* class_name = descriptor->GetClassName().GetCString();
743
744    if (!class_name || !*class_name)
745        return false;
746
747    if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
748    {
749        if (descriptor->IsTagged())
750        {
751            // we have a call to get info and value bits in the tagged descriptor. but we prefer not to cast and replicate them
752            int64_t value = (valobj_addr & ~0x0000000000000000FFL) >> 8;
753            uint64_t i_bits = (valobj_addr & 0xF0) >> 4;
754
755            switch (i_bits)
756            {
757                case 0:
758                    stream.Printf("(char)%hhd",(char)value);
759                    break;
760                case 4:
761                    stream.Printf("(short)%hd",(short)value);
762                    break;
763                case 8:
764                    stream.Printf("(int)%d",(int)value);
765                    break;
766                case 12:
767                    stream.Printf("(long)%" PRId64,value);
768                    break;
769                default:
770                    stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value);
771                    break;
772            }
773            return true;
774        }
775        else
776        {
777            Error error;
778            uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
779            uint64_t data_location = valobj_addr + 2*ptr_size;
780            uint64_t value = 0;
781            if (error.Fail())
782                return false;
783            switch (data_type)
784            {
785                case 1: // 0B00001
786                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
787                    if (error.Fail())
788                        return false;
789                    stream.Printf("(char)%hhd",(char)value);
790                    break;
791                case 2: // 0B0010
792                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
793                    if (error.Fail())
794                        return false;
795                    stream.Printf("(short)%hd",(short)value);
796                    break;
797                case 3: // 0B0011
798                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
799                    if (error.Fail())
800                        return false;
801                    stream.Printf("(int)%d",(int)value);
802                    break;
803                case 17: // 0B10001
804                    data_location += 8;
805                case 4: // 0B0100
806                    value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
807                    if (error.Fail())
808                        return false;
809                    stream.Printf("(long)%" PRId64,value);
810                    break;
811                case 5: // 0B0101
812                {
813                    uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
814                    if (error.Fail())
815                        return false;
816                    float flt_value = *((float*)&flt_as_int);
817                    stream.Printf("(float)%f",flt_value);
818                    break;
819                }
820                case 6: // 0B0110
821                {
822                    uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
823                    if (error.Fail())
824                        return false;
825                    double dbl_value = *((double*)&dbl_as_lng);
826                    stream.Printf("(double)%g",dbl_value);
827                    break;
828                }
829                default:
830                    stream.Printf("absurd: dt=%d",data_type);
831                    break;
832            }
833            return true;
834        }
835    }
836    else
837    {
838        // similar to ExtractValueFromObjCExpression but uses summary instead of value
839        StreamString expr_path_stream;
840        valobj.GetExpressionPath(expr_path_stream, false);
841        StreamString expr;
842        expr.Printf("(NSString*)[%s stringValue]",expr_path_stream.GetData());
843        ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
844        lldb::ValueObjectSP result_sp;
845        Target* target = exe_ctx.GetTargetPtr();
846        StackFrame* stack_frame = exe_ctx.GetFramePtr();
847        if (!target || !stack_frame)
848            return false;
849
850        EvaluateExpressionOptions options;
851        options.SetCoerceToId(false)
852        .SetUnwindOnError(true)
853        .SetKeepInMemory(true)
854        .SetUseDynamic(lldb::eDynamicCanRunTarget);
855
856        target->EvaluateExpression(expr.GetData(),
857                                   stack_frame,
858                                   result_sp,
859                                   options);
860        if (!result_sp)
861            return false;
862        stream.Printf("%s",result_sp->GetSummaryAsCString());
863        return true;
864    }
865}
866
867bool
868lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
869{
870    ProcessSP process_sp = valobj.GetProcessSP();
871    if (!process_sp)
872        return false;
873
874    ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
875
876    if (!runtime)
877        return false;
878
879    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
880
881    if (!descriptor.get() || !descriptor->IsValid())
882        return false;
883
884    uint32_t ptr_size = process_sp->GetAddressByteSize();
885
886    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
887
888    if (!valobj_addr)
889        return false;
890
891    const char* class_name = descriptor->GetClassName().GetCString();
892
893    if (!class_name || !*class_name)
894        return false;
895
896    uint64_t info_bits_location = valobj_addr + ptr_size;
897    if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
898        info_bits_location += 3;
899
900        Error error;
901
902    uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error);
903    if (error.Fail())
904        return false;
905
906    bool is_mutable = (info_bits & 1) == 1;
907    bool is_inline = (info_bits & 0x60) == 0;
908    bool has_explicit_length = (info_bits & (1 | 4)) != 4;
909    bool is_unicode = (info_bits & 0x10) == 0x10;
910    bool is_special = strcmp(class_name,"NSPathStore2") == 0;
911
912    if (strcmp(class_name,"NSString") &&
913        strcmp(class_name,"CFStringRef") &&
914        strcmp(class_name,"CFMutableStringRef") &&
915        strcmp(class_name,"__NSCFConstantString") &&
916        strcmp(class_name,"__NSCFString") &&
917        strcmp(class_name,"NSCFConstantString") &&
918        strcmp(class_name,"NSCFString") &&
919        strcmp(class_name,"NSPathStore2"))
920    {
921        // probably not one of us - bail out
922        return false;
923    }
924
925    if (is_mutable)
926    {
927        uint64_t location = 2 * ptr_size + valobj_addr;
928        location = process_sp->ReadPointerFromMemory(location, error);
929        if (error.Fail())
930            return false;
931        if (has_explicit_length and is_unicode)
932            return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8,location, process_sp, stream, '@');
933        else
934        {
935            location++;
936            lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0));
937            size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error);
938            if (error.Fail())
939                return false;
940            if (data_read)
941                stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes());
942                return true;
943        }
944    }
945    else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable)
946    {
947        uint64_t location = 3 * ptr_size + valobj_addr;
948        lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0));
949        size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error);
950        if (error.Fail())
951            return false;
952        if (data_read)
953            stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes());
954            return true;
955    }
956    else if (is_unicode)
957    {
958        uint64_t location = valobj_addr + ptr_size + 4 + (ptr_size == 8 ? 4 : 0);
959        if (is_inline)
960        {
961            if (!has_explicit_length)
962            {
963                stream.Printf("found new combo");
964                return true;
965            }
966            else
967                location += ptr_size;
968                }
969        else
970        {
971            location = process_sp->ReadPointerFromMemory(location, error);
972            if (error.Fail())
973                return false;
974        }
975        return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
976    }
977    else if (is_special)
978    {
979        uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8);
980        return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@');
981    }
982    else if (is_inline)
983    {
984        uint64_t location = valobj_addr + ptr_size + 4 + (ptr_size == 8 ? 4 : 0);
985        if (!has_explicit_length)
986            location++;
987        lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0));
988        size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error);
989        if (error.Fail())
990            return false;
991        if (data_read)
992            stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes());
993            return true;
994    }
995    else
996    {
997        uint64_t location = valobj_addr + ptr_size + 4 + (ptr_size == 8 ? 4 : 0);
998        location = process_sp->ReadPointerFromMemory(location, error);
999        if (error.Fail())
1000            return false;
1001        lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0));
1002        size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error);
1003        if (error.Fail())
1004            return false;
1005        if (data_read)
1006            stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes());
1007            return true;
1008    }
1009
1010    stream.Printf("class name = %s",class_name);
1011    return true;
1012
1013}
1014
1015bool
1016lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1017{
1018    TargetSP target_sp(valobj.GetTargetSP());
1019    if (!target_sp)
1020        return false;
1021    uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
1022    uint64_t pointee = valobj.GetValueAsUnsigned(0);
1023    if (!pointee)
1024        return false;
1025    pointee += addr_size;
1026    ClangASTType type(valobj.GetClangAST(),valobj.GetClangType());
1027    ExecutionContext exe_ctx(target_sp,false);
1028    ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointee, exe_ctx, type));
1029    if (!child_ptr_sp)
1030        return false;
1031    DataExtractor data;
1032    child_ptr_sp->GetData(data);
1033    ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type));
1034    child_sp->GetValueAsUnsigned(0);
1035    if (child_sp)
1036        return NSStringSummaryProvider(*child_sp, stream);
1037    return false;
1038}
1039
1040bool
1041lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1042{
1043    return NSAttributedStringSummaryProvider(valobj, stream);
1044}
1045
1046bool
1047lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream)
1048{
1049    stream.Printf("%s",valobj.GetObjectDescription());
1050    return true;
1051}
1052
1053bool
1054lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream)
1055{
1056    const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(),
1057                                                            valobj.GetClangAST(),
1058                                                            NULL);
1059
1060    ValueObjectSP real_guy_sp = valobj.GetSP();
1061
1062    if (type_info & ClangASTContext::eTypeIsPointer)
1063    {
1064        Error err;
1065        real_guy_sp = valobj.Dereference(err);
1066        if (err.Fail() || !real_guy_sp)
1067            return false;
1068    }
1069    else if (type_info & ClangASTContext::eTypeIsReference)
1070    {
1071        real_guy_sp =  valobj.GetChildAtIndex(0, true);
1072        if (!real_guy_sp)
1073            return false;
1074    }
1075    uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
1076    if (value == 0)
1077    {
1078        stream.Printf("NO");
1079        return true;
1080    }
1081    stream.Printf("YES");
1082    return true;
1083}
1084
1085template <bool is_sel_ptr>
1086bool
1087lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream)
1088{
1089    lldb::addr_t data_address = LLDB_INVALID_ADDRESS;
1090
1091    if (is_sel_ptr)
1092        data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1093    else
1094        data_address = valobj.GetAddressOf();
1095
1096    if (data_address == LLDB_INVALID_ADDRESS)
1097        return false;
1098
1099    ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1100
1101    void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr();
1102    ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type));
1103
1104    ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar));
1105
1106    stream.Printf("%s",valobj_sp->GetSummaryAsCString());
1107    return true;
1108}
1109
1110lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1111SyntheticChildrenFrontEnd(*valobj_sp.get()),
1112m_exe_ctx_ref(),
1113m_ptr_size(8),
1114m_data_32(NULL),
1115m_data_64(NULL)
1116{
1117    if (valobj_sp)
1118    {
1119        m_id_type = ClangASTType(valobj_sp->GetClangAST(),valobj_sp->GetClangAST()->ObjCBuiltinIdTy.getAsOpaquePtr());
1120        Update();
1121    }
1122}
1123
1124size_t
1125lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren ()
1126{
1127    if (m_data_32)
1128        return m_data_32->_used;
1129    if (m_data_64)
1130        return m_data_64->_used;
1131    return 0;
1132}
1133
1134lldb::ValueObjectSP
1135lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1136{
1137    if (!m_data_32 && !m_data_64)
1138        return lldb::ValueObjectSP();
1139    if (idx >= CalculateNumChildren())
1140        return lldb::ValueObjectSP();
1141    lldb::addr_t object_at_idx = (m_data_32 ? m_data_32->_data : m_data_64->_data);
1142    object_at_idx += (idx * m_ptr_size);
1143    StreamString idx_name;
1144    idx_name.Printf("[%zu]",idx);
1145    lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(),
1146                                                                              object_at_idx,
1147                                                                              m_exe_ctx_ref,
1148                                                                              m_id_type);
1149    m_children.push_back(retval_sp);
1150    return retval_sp;
1151}
1152
1153bool
1154lldb_private::formatters::NSArrayMSyntheticFrontEnd::Update()
1155{
1156    m_children.clear();
1157    ValueObjectSP valobj_sp = m_backend.GetSP();
1158    m_ptr_size = 0;
1159    delete m_data_32;
1160    m_data_32 = NULL;
1161    delete m_data_64;
1162    m_data_64 = NULL;
1163    if (valobj_sp->IsDynamic())
1164        valobj_sp = valobj_sp->GetStaticValue();
1165    if (!valobj_sp)
1166        return false;
1167    m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1168    Error error;
1169    if (valobj_sp->IsPointerType())
1170    {
1171        valobj_sp = valobj_sp->Dereference(error);
1172        if (error.Fail() || !valobj_sp)
1173            return false;
1174    }
1175    error.Clear();
1176    lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1177    if (!process_sp)
1178        return false;
1179    m_ptr_size = process_sp->GetAddressByteSize();
1180    uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
1181    if (m_ptr_size == 4)
1182    {
1183        m_data_32 = new DataDescriptor_32();
1184        process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
1185    }
1186    else
1187    {
1188        m_data_64 = new DataDescriptor_64();
1189        process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
1190    }
1191    if (error.Fail())
1192        return false;
1193    return false;
1194}
1195
1196bool
1197lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren ()
1198{
1199    return true;
1200}
1201
1202static uint32_t
1203ExtractIndexFromString (const char* item_name)
1204{
1205    if (!item_name || !*item_name)
1206        return UINT32_MAX;
1207    if (*item_name != '[')
1208        return UINT32_MAX;
1209    item_name++;
1210    uint32_t idx = 0;
1211    while(*item_name)
1212    {
1213        char x = *item_name;
1214        if (x == ']')
1215            break;
1216        if (x < '0' || x > '9')
1217            return UINT32_MAX;
1218        idx = 10*idx + (x-'0');
1219        item_name++;
1220    }
1221    return idx;
1222}
1223
1224size_t
1225lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1226{
1227    if (!m_data_32 && !m_data_64)
1228        return UINT32_MAX;
1229    const char* item_name = name.GetCString();
1230    uint32_t idx = ExtractIndexFromString(item_name);
1231    if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1232        return UINT32_MAX;
1233    return idx;
1234}
1235
1236lldb_private::formatters::NSArrayMSyntheticFrontEnd::~NSArrayMSyntheticFrontEnd ()
1237{
1238    delete m_data_32;
1239    m_data_32 = NULL;
1240    delete m_data_64;
1241    m_data_64 = NULL;
1242}
1243
1244lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1245SyntheticChildrenFrontEnd(*valobj_sp.get()),
1246m_exe_ctx_ref(),
1247m_ptr_size(8),
1248m_items(0),
1249m_data_ptr(0)
1250{
1251    if (valobj_sp)
1252    {
1253        m_id_type = ClangASTType(valobj_sp->GetClangAST(),valobj_sp->GetClangAST()->ObjCBuiltinIdTy.getAsOpaquePtr());
1254        Update();
1255    }
1256}
1257
1258lldb_private::formatters::NSArrayISyntheticFrontEnd::~NSArrayISyntheticFrontEnd ()
1259{
1260}
1261
1262size_t
1263lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1264{
1265    const char* item_name = name.GetCString();
1266    uint32_t idx = ExtractIndexFromString(item_name);
1267    if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1268        return UINT32_MAX;
1269    return idx;
1270}
1271
1272size_t
1273lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren ()
1274{
1275    return m_items;
1276}
1277
1278bool
1279lldb_private::formatters::NSArrayISyntheticFrontEnd::Update()
1280{
1281    m_ptr_size = 0;
1282    m_items = 0;
1283    m_data_ptr = 0;
1284    m_children.clear();
1285    ValueObjectSP valobj_sp = m_backend.GetSP();
1286    if (valobj_sp->IsDynamic())
1287        valobj_sp = valobj_sp->GetStaticValue();
1288    if (!valobj_sp)
1289        return false;
1290    m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1291    Error error;
1292    if (valobj_sp->IsPointerType())
1293    {
1294        valobj_sp = valobj_sp->Dereference(error);
1295        if (error.Fail() || !valobj_sp)
1296            return false;
1297    }
1298    error.Clear();
1299    lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1300    if (!process_sp)
1301        return false;
1302    m_ptr_size = process_sp->GetAddressByteSize();
1303    uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
1304    m_items = process_sp->ReadPointerFromMemory(data_location, error);
1305    if (error.Fail())
1306        return false;
1307    m_data_ptr = data_location+m_ptr_size;
1308    return false;
1309}
1310
1311bool
1312lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren ()
1313{
1314    return true;
1315}
1316
1317lldb::ValueObjectSP
1318lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx)
1319{
1320    if (idx >= CalculateNumChildren())
1321        return lldb::ValueObjectSP();
1322    lldb::addr_t object_at_idx = m_data_ptr;
1323    object_at_idx += (idx * m_ptr_size);
1324    ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1325    if (!process_sp)
1326        return lldb::ValueObjectSP();
1327    Error error;
1328    object_at_idx = process_sp->ReadPointerFromMemory(object_at_idx, error);
1329    if (error.Fail())
1330        return lldb::ValueObjectSP();
1331    StreamString expr;
1332    expr.Printf("(id)%" PRIu64,object_at_idx);
1333    StreamString idx_name;
1334    idx_name.Printf("[%zu]",idx);
1335    lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
1336    m_children.push_back(retval_sp);
1337    return retval_sp;
1338}
1339
1340SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
1341{
1342    lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
1343    if (!process_sp)
1344        return NULL;
1345    ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1346    if (!runtime)
1347        return NULL;
1348
1349    if (!valobj_sp->IsPointerType())
1350    {
1351        Error error;
1352        valobj_sp = valobj_sp->AddressOf(error);
1353        if (error.Fail() || !valobj_sp)
1354            return NULL;
1355    }
1356
1357    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
1358
1359    if (!descriptor.get() || !descriptor->IsValid())
1360        return NULL;
1361
1362    const char* class_name = descriptor->GetClassName().GetCString();
1363
1364    if (!class_name || !*class_name)
1365        return NULL;
1366
1367    if (!strcmp(class_name,"__NSArrayI"))
1368    {
1369        return (new NSArrayISyntheticFrontEnd(valobj_sp));
1370    }
1371    else if (!strcmp(class_name,"__NSArrayM"))
1372    {
1373        return (new NSArrayMSyntheticFrontEnd(valobj_sp));
1374    }
1375    else
1376    {
1377        return (new NSArrayCodeRunningSyntheticFrontEnd(valobj_sp));
1378    }
1379}
1380
1381lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1382SyntheticChildrenFrontEnd(*valobj_sp.get())
1383{}
1384
1385size_t
1386lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
1387{
1388    uint64_t count = 0;
1389    if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
1390        return count;
1391    return 0;
1392}
1393
1394lldb::ValueObjectSP
1395lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1396{
1397    StreamString idx_name;
1398    idx_name.Printf("[%zu]",idx);
1399    lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx);
1400    if (valobj_sp)
1401        valobj_sp->SetName(ConstString(idx_name.GetData()));
1402    return valobj_sp;
1403}
1404
1405bool
1406lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::Update()
1407{
1408    return false;
1409}
1410
1411bool
1412lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::MightHaveChildren ()
1413{
1414    return true;
1415}
1416
1417size_t
1418lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1419{
1420    return 0;
1421}
1422
1423lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::~NSArrayCodeRunningSyntheticFrontEnd ()
1424{}
1425
1426SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
1427{
1428
1429    lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
1430    if (!process_sp)
1431        return NULL;
1432    ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
1433    if (!runtime)
1434        return NULL;
1435
1436    if (!valobj_sp->IsPointerType())
1437    {
1438        Error error;
1439        valobj_sp = valobj_sp->AddressOf(error);
1440        if (error.Fail() || !valobj_sp)
1441            return NULL;
1442    }
1443
1444    ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
1445
1446    if (!descriptor.get() || !descriptor->IsValid())
1447        return NULL;
1448
1449    const char* class_name = descriptor->GetClassName().GetCString();
1450
1451    if (!class_name || !*class_name)
1452        return NULL;
1453
1454    if (!strcmp(class_name,"__NSDictionaryI"))
1455    {
1456        return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
1457    }
1458    else if (!strcmp(class_name,"__NSDictionaryM"))
1459    {
1460        return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
1461    }
1462    else
1463    {
1464        return (new NSDictionaryCodeRunningSyntheticFrontEnd(valobj_sp));
1465    }
1466}
1467
1468lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1469SyntheticChildrenFrontEnd(*valobj_sp.get())
1470{}
1471
1472size_t
1473lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
1474{
1475    uint64_t count = 0;
1476    if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
1477        return count;
1478    return 0;
1479}
1480
1481lldb::ValueObjectSP
1482lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1483{
1484    StreamString idx_name;
1485    idx_name.Printf("[%zu]",idx);
1486    StreamString valobj_expr_path;
1487    m_backend.GetExpressionPath(valobj_expr_path, false);
1488    StreamString key_fetcher_expr;
1489    key_fetcher_expr.Printf("(id)[(NSArray*)[%s allKeys] objectAtIndex:%zu]",valobj_expr_path.GetData(),idx);
1490    StreamString value_fetcher_expr;
1491    value_fetcher_expr.Printf("(id)[%s objectForKey:%s]",valobj_expr_path.GetData(),key_fetcher_expr.GetData());
1492    StreamString object_fetcher_expr;
1493    object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData());
1494    lldb::ValueObjectSP child_sp;
1495    m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp,
1496                                                EvaluateExpressionOptions().SetKeepInMemory(true));
1497    if (child_sp)
1498        child_sp->SetName(ConstString(idx_name.GetData()));
1499    return child_sp;
1500}
1501
1502bool
1503lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update()
1504{
1505    return false;
1506}
1507
1508bool
1509lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren ()
1510{
1511    return true;
1512}
1513
1514size_t
1515lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1516{
1517    return 0;
1518}
1519
1520lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::~NSDictionaryCodeRunningSyntheticFrontEnd ()
1521{}
1522
1523lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1524    SyntheticChildrenFrontEnd(*valobj_sp.get()),
1525    m_exe_ctx_ref(),
1526    m_ptr_size(8),
1527    m_data_32(NULL),
1528    m_data_64(NULL)
1529{
1530    if (valobj_sp)
1531        Update();
1532}
1533
1534lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd ()
1535{
1536    delete m_data_32;
1537    m_data_32 = NULL;
1538    delete m_data_64;
1539    m_data_64 = NULL;
1540}
1541
1542size_t
1543lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1544{
1545    const char* item_name = name.GetCString();
1546    uint32_t idx = ExtractIndexFromString(item_name);
1547    if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1548        return UINT32_MAX;
1549    return idx;
1550}
1551
1552size_t
1553lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren ()
1554{
1555    if (!m_data_32 && !m_data_64)
1556        return 0;
1557    return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1558}
1559
1560bool
1561lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
1562{
1563    m_children.clear();
1564    delete m_data_32;
1565    m_data_32 = NULL;
1566    delete m_data_64;
1567    m_data_64 = NULL;
1568    m_ptr_size = 0;
1569    ValueObjectSP valobj_sp = m_backend.GetSP();
1570    if (!valobj_sp)
1571        return false;
1572    if (valobj_sp->IsDynamic())
1573        valobj_sp = valobj_sp->GetStaticValue();
1574    if (!valobj_sp)
1575        return false;
1576    m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1577    Error error;
1578    if (valobj_sp->IsPointerType())
1579    {
1580        valobj_sp = valobj_sp->Dereference(error);
1581        if (error.Fail() || !valobj_sp)
1582            return false;
1583    }
1584    error.Clear();
1585    lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1586    if (!process_sp)
1587        return false;
1588    m_ptr_size = process_sp->GetAddressByteSize();
1589    uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
1590    if (m_ptr_size == 4)
1591    {
1592        m_data_32 = new DataDescriptor_32();
1593        process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
1594    }
1595    else
1596    {
1597        m_data_64 = new DataDescriptor_64();
1598        process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
1599    }
1600    if (error.Fail())
1601        return false;
1602    m_data_ptr = data_location + m_ptr_size;
1603    return false;
1604}
1605
1606bool
1607lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren ()
1608{
1609    return true;
1610}
1611
1612lldb::ValueObjectSP
1613lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx)
1614{
1615    uint32_t num_children = CalculateNumChildren();
1616
1617    if (idx >= num_children)
1618        return lldb::ValueObjectSP();
1619
1620    if (m_children.empty())
1621    {
1622        // do the scan phase
1623        lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1624
1625        uint32_t tries = 0;
1626        uint32_t test_idx = 0;
1627
1628        while(tries < num_children)
1629        {
1630            key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size);
1631            val_at_idx = key_at_idx + m_ptr_size;
1632            ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1633            if (!process_sp)
1634                return lldb::ValueObjectSP();
1635            Error error;
1636            key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1637            if (error.Fail())
1638                return lldb::ValueObjectSP();
1639            val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1640            if (error.Fail())
1641                return lldb::ValueObjectSP();
1642
1643            test_idx++;
1644
1645            if (!key_at_idx || !val_at_idx)
1646                continue;
1647            tries++;
1648
1649            DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
1650
1651            m_children.push_back(descriptor);
1652        }
1653    }
1654
1655    if (idx >= m_children.size()) // should never happen
1656        return lldb::ValueObjectSP();
1657
1658    DictionaryItemDescriptor &dict_item = m_children[idx];
1659    if (!dict_item.valobj_sp)
1660    {
1661        // make the new ValueObject
1662        StreamString expr;
1663        expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = (id)%" PRIu64 " ; _lldb_valgen_item.value = (id)%" PRIu64 "; _lldb_valgen_item;",dict_item.key_ptr,dict_item.val_ptr);
1664        StreamString idx_name;
1665        idx_name.Printf("[%zu]",idx);
1666        dict_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
1667    }
1668    return dict_item.valobj_sp;
1669}
1670
1671lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1672    SyntheticChildrenFrontEnd(*valobj_sp.get()),
1673    m_exe_ctx_ref(),
1674    m_ptr_size(8),
1675    m_data_32(NULL),
1676    m_data_64(NULL)
1677{
1678    if (valobj_sp)
1679        Update ();
1680}
1681
1682lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd ()
1683{
1684    delete m_data_32;
1685    m_data_32 = NULL;
1686    delete m_data_64;
1687    m_data_64 = NULL;
1688}
1689
1690size_t
1691lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1692{
1693    const char* item_name = name.GetCString();
1694    uint32_t idx = ExtractIndexFromString(item_name);
1695    if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1696        return UINT32_MAX;
1697    return idx;
1698}
1699
1700size_t
1701lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren ()
1702{
1703    if (!m_data_32 && !m_data_64)
1704        return 0;
1705    return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1706}
1707
1708bool
1709lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
1710{
1711    m_children.clear();
1712    ValueObjectSP valobj_sp = m_backend.GetSP();
1713    m_ptr_size = 0;
1714    delete m_data_32;
1715    m_data_32 = NULL;
1716    delete m_data_64;
1717    m_data_64 = NULL;
1718    if (!valobj_sp)
1719        return false;
1720    if (valobj_sp->IsDynamic())
1721        valobj_sp = valobj_sp->GetStaticValue();
1722    if (!valobj_sp)
1723        return false;
1724    m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1725    Error error;
1726    if (valobj_sp->IsPointerType())
1727    {
1728        valobj_sp = valobj_sp->Dereference(error);
1729        if (error.Fail() || !valobj_sp)
1730            return false;
1731    }
1732    error.Clear();
1733    lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1734    if (!process_sp)
1735        return false;
1736    m_ptr_size = process_sp->GetAddressByteSize();
1737    uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
1738    if (m_ptr_size == 4)
1739    {
1740        m_data_32 = new DataDescriptor_32();
1741        process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
1742    }
1743    else
1744    {
1745        m_data_64 = new DataDescriptor_64();
1746        process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
1747    }
1748    if (error.Fail())
1749        return false;
1750    return false;
1751}
1752
1753bool
1754lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren ()
1755{
1756    return true;
1757}
1758
1759lldb::ValueObjectSP
1760lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1761{
1762    lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
1763    lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
1764
1765    uint32_t num_children = CalculateNumChildren();
1766
1767    if (idx >= num_children)
1768        return lldb::ValueObjectSP();
1769
1770    if (m_children.empty())
1771    {
1772        // do the scan phase
1773        lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1774
1775        uint32_t tries = 0;
1776        uint32_t test_idx = 0;
1777
1778        while(tries < num_children)
1779        {
1780            key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1781            val_at_idx = m_values_ptr + (test_idx * m_ptr_size);;
1782            ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1783            if (!process_sp)
1784                return lldb::ValueObjectSP();
1785            Error error;
1786            key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1787            if (error.Fail())
1788                return lldb::ValueObjectSP();
1789            val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1790            if (error.Fail())
1791                return lldb::ValueObjectSP();
1792
1793            test_idx++;
1794
1795            if (!key_at_idx || !val_at_idx)
1796                continue;
1797            tries++;
1798
1799            DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
1800
1801            m_children.push_back(descriptor);
1802        }
1803    }
1804
1805    if (idx >= m_children.size()) // should never happen
1806        return lldb::ValueObjectSP();
1807
1808    DictionaryItemDescriptor &dict_item = m_children[idx];
1809    if (!dict_item.valobj_sp)
1810    {
1811        // make the new ValueObject
1812        StreamString expr;
1813        expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = (id)%" PRIu64 " ; _lldb_valgen_item.value = (id)%" PRIu64 "; _lldb_valgen_item;",dict_item.key_ptr,dict_item.val_ptr);
1814        StreamString idx_name;
1815        idx_name.Printf("[%zu]",idx);
1816        dict_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
1817    }
1818    return dict_item.valobj_sp;
1819}
1820
1821lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::LibcxxVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1822    SyntheticChildrenFrontEnd(*valobj_sp.get()),
1823    m_exe_ctx_ref(),
1824    m_count(0),
1825    m_base_data_address(0),
1826    m_options()
1827    {
1828        if (valobj_sp)
1829            Update();
1830        m_options.SetCoerceToId(false)
1831                 .SetUnwindOnError(true)
1832                 .SetKeepInMemory(true)
1833                 .SetUseDynamic(lldb::eDynamicCanRunTarget);
1834    }
1835
1836size_t
1837lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
1838{
1839    return m_count;
1840}
1841
1842lldb::ValueObjectSP
1843lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1844{
1845    if (idx >= m_count)
1846        return ValueObjectSP();
1847    if (m_base_data_address == 0 || m_count == 0)
1848        return ValueObjectSP();
1849    size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
1850    size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
1851    lldb::addr_t byte_location = m_base_data_address + byte_idx;
1852    ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
1853    if (!process_sp)
1854        return ValueObjectSP();
1855    uint8_t byte = 0;
1856    uint8_t mask = 0;
1857    Error err;
1858    size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
1859    if (err.Fail() || bytes_read == 0)
1860        return ValueObjectSP();
1861    switch (bit_index)
1862    {
1863        case 0:
1864            mask = 1; break;
1865        case 1:
1866            mask = 2; break;
1867        case 2:
1868            mask = 4; break;
1869        case 3:
1870            mask = 8; break;
1871        case 4:
1872            mask = 16; break;
1873        case 5:
1874            mask = 32; break;
1875        case 6:
1876            mask = 64; break;
1877        case 7:
1878            mask = 128; break;
1879        default:
1880            return ValueObjectSP();
1881    }
1882    bool bit_set = ((byte & mask) != 0);
1883    Target& target(process_sp->GetTarget());
1884    ValueObjectSP retval_sp;
1885    if (bit_set)
1886        target.EvaluateExpression("(bool)true", NULL, retval_sp);
1887    else
1888        target.EvaluateExpression("(bool)false", NULL, retval_sp);
1889    StreamString name; name.Printf("[%zu]",idx);
1890    if (retval_sp)
1891        retval_sp->SetName(ConstString(name.GetData()));
1892    return retval_sp;
1893}
1894
1895/*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
1896    __begin_ = 0x00000001001000e0
1897    __size_ = 56
1898    __cap_alloc_ = {
1899        std::__1::__libcpp_compressed_pair_imp<unsigned long, std::__1::allocator<unsigned long> > = {
1900            __first_ = 1
1901        }
1902    }
1903}*/
1904
1905bool
1906lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update()
1907{
1908    ValueObjectSP valobj_sp = m_backend.GetSP();
1909    if (!valobj_sp)
1910        return false;
1911    if (valobj_sp->IsDynamic())
1912        valobj_sp = valobj_sp->GetStaticValue();
1913    if (!valobj_sp)
1914        return false;
1915    m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1916    ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName(ConstString("__size_"), true));
1917    if (!size_sp)
1918        return false;
1919    m_count = size_sp->GetValueAsUnsigned(0);
1920    if (!m_count)
1921        return true;
1922    ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true));
1923    if (!begin_sp)
1924    {
1925        m_count = 0;
1926        return false;
1927    }
1928    m_base_data_address = begin_sp->GetValueAsUnsigned(0);
1929    if (!m_base_data_address)
1930    {
1931        m_count = 0;
1932        return false;
1933    }
1934    return true;
1935}
1936
1937bool
1938lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::MightHaveChildren ()
1939{
1940    return true;
1941}
1942
1943size_t
1944lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1945{
1946    if (!m_count || !m_base_data_address)
1947        return UINT32_MAX;
1948    const char* item_name = name.GetCString();
1949    uint32_t idx = ExtractIndexFromString(item_name);
1950    if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1951        return UINT32_MAX;
1952    return idx;
1953}
1954
1955lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::~LibcxxVectorBoolSyntheticFrontEnd ()
1956{}
1957
1958SyntheticChildrenFrontEnd*
1959lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
1960{
1961    if (!valobj_sp)
1962        return NULL;
1963    return (new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp));
1964}
1965
1966lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::LibstdcppVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
1967SyntheticChildrenFrontEnd(*valobj_sp.get()),
1968m_exe_ctx_ref(),
1969m_count(0),
1970m_base_data_address(0),
1971m_options()
1972{
1973    if (valobj_sp)
1974        Update();
1975    m_options.SetCoerceToId(false)
1976    .SetUnwindOnError(true)
1977    .SetKeepInMemory(true)
1978    .SetUseDynamic(lldb::eDynamicCanRunTarget);
1979}
1980
1981size_t
1982lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
1983{
1984    return m_count;
1985}
1986
1987lldb::ValueObjectSP
1988lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1989{
1990    if (idx >= m_count)
1991        return ValueObjectSP();
1992    if (m_base_data_address == 0 || m_count == 0)
1993        return ValueObjectSP();
1994    size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
1995    size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
1996    lldb::addr_t byte_location = m_base_data_address + byte_idx;
1997    ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
1998    if (!process_sp)
1999        return ValueObjectSP();
2000    uint8_t byte = 0;
2001    uint8_t mask = 0;
2002    Error err;
2003    size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
2004    if (err.Fail() || bytes_read == 0)
2005        return ValueObjectSP();
2006    switch (bit_index)
2007    {
2008        case 0:
2009            mask = 1; break;
2010        case 1:
2011            mask = 2; break;
2012        case 2:
2013            mask = 4; break;
2014        case 3:
2015            mask = 8; break;
2016        case 4:
2017            mask = 16; break;
2018        case 5:
2019            mask = 32; break;
2020        case 6:
2021            mask = 64; break;
2022        case 7:
2023            mask = 128; break;
2024        default:
2025            return ValueObjectSP();
2026    }
2027    bool bit_set = ((byte & mask) != 0);
2028    Target& target(process_sp->GetTarget());
2029    ValueObjectSP retval_sp;
2030    if (bit_set)
2031        target.EvaluateExpression("(bool)true", NULL, retval_sp);
2032    else
2033        target.EvaluateExpression("(bool)false", NULL, retval_sp);
2034    StreamString name; name.Printf("[%zu]",idx);
2035    if (retval_sp)
2036        retval_sp->SetName(ConstString(name.GetData()));
2037    return retval_sp;
2038}
2039
2040/*((std::vector<std::allocator<bool> >) vBool = {
2041 (std::_Bvector_base<std::allocator<bool> >) std::_Bvector_base<std::allocator<bool> > = {
2042 (std::_Bvector_base<std::allocator<bool> >::_Bvector_impl) _M_impl = {
2043 (std::_Bit_iterator) _M_start = {
2044 (std::_Bit_iterator_base) std::_Bit_iterator_base = {
2045 (_Bit_type *) _M_p = 0x0016b160
2046 (unsigned int) _M_offset = 0
2047 }
2048 }
2049 (std::_Bit_iterator) _M_finish = {
2050 (std::_Bit_iterator_base) std::_Bit_iterator_base = {
2051 (_Bit_type *) _M_p = 0x0016b16c
2052 (unsigned int) _M_offset = 16
2053 }
2054 }
2055 (_Bit_type *) _M_end_of_storage = 0x0016b170
2056 }
2057 }
2058 }
2059*/
2060
2061bool
2062lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::Update()
2063{
2064    ValueObjectSP valobj_sp = m_backend.GetSP();
2065    if (!valobj_sp)
2066        return false;
2067    if (valobj_sp->IsDynamic())
2068        valobj_sp = valobj_sp->GetStaticValue();
2069    if (!valobj_sp)
2070        return false;
2071    m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
2072
2073    ValueObjectSP m_impl_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_impl"), true));
2074    if (!m_impl_sp)
2075        return false;
2076
2077    ValueObjectSP m_start_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_start"), true));
2078    ValueObjectSP m_finish_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_finish"), true));
2079
2080    ValueObjectSP start_p_sp, finish_p_sp, finish_offset_sp;
2081
2082    if (!m_start_sp || !m_finish_sp)
2083        return false;
2084
2085    start_p_sp = m_start_sp->GetChildMemberWithName(ConstString("_M_p"), true);
2086    finish_p_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_p"), true);
2087    finish_offset_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_offset"), true);
2088
2089    if (!start_p_sp || !finish_offset_sp || !finish_p_sp)
2090        return false;
2091
2092    m_base_data_address = start_p_sp->GetValueAsUnsigned(0);
2093    if (!m_base_data_address)
2094        return false;
2095
2096    lldb::addr_t end_data_address(finish_p_sp->GetValueAsUnsigned(0));
2097    if (!end_data_address)
2098        return false;
2099
2100    if (end_data_address < m_base_data_address)
2101        return false;
2102    else
2103        m_count = finish_offset_sp->GetValueAsUnsigned(0) + (end_data_address-m_base_data_address)*8;
2104
2105    return true;
2106}
2107
2108bool
2109lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::MightHaveChildren ()
2110{
2111    return true;
2112}
2113
2114size_t
2115lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
2116{
2117    if (!m_count || !m_base_data_address)
2118        return UINT32_MAX;
2119    const char* item_name = name.GetCString();
2120    uint32_t idx = ExtractIndexFromString(item_name);
2121    if (idx < UINT32_MAX && idx >= CalculateNumChildren())
2122        return UINT32_MAX;
2123    return idx;
2124}
2125
2126lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::~LibstdcppVectorBoolSyntheticFrontEnd ()
2127{}
2128
2129SyntheticChildrenFrontEnd*
2130lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
2131{
2132    if (!valobj_sp)
2133        return NULL;
2134    return (new LibstdcppVectorBoolSyntheticFrontEnd(valobj_sp));
2135}
2136
2137template bool
2138lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ;
2139
2140template bool
2141lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ;
2142
2143template bool
2144lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
2145
2146template bool
2147lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
2148
2149template bool
2150lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ;
2151
2152template bool
2153lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ;
2154