1 //===-- NSDictionary.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 // C Includes
11 // C++ Includes
12 #include <mutex>
13 
14 // Other libraries and framework includes
15 #include "clang/AST/DeclCXX.h"
16 
17 // Project includes
18 #include "NSDictionary.h"
19 
20 #include "lldb/Core/DataBufferHeap.h"
21 #include "lldb/Core/Error.h"
22 #include "lldb/Core/Stream.h"
23 #include "lldb/Core/ValueObject.h"
24 #include "lldb/Core/ValueObjectConstResult.h"
25 #include "lldb/DataFormatters/FormattersHelpers.h"
26 #include "lldb/Host/Endian.h"
27 #include "lldb/Symbol/ClangASTContext.h"
28 #include "lldb/Target/Language.h"
29 #include "lldb/Target/ObjCLanguageRuntime.h"
30 #include "lldb/Target/StackFrame.h"
31 #include "lldb/Target/Target.h"
32 
33 using namespace lldb;
34 using namespace lldb_private;
35 using namespace lldb_private::formatters;
36 
37 std::map<ConstString, CXXFunctionSummaryFormat::Callback>&
38 NSDictionary_Additionals::GetAdditionalSummaries ()
39 {
40     static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
41     return g_map;
42 }
43 
44 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>&
45 NSDictionary_Additionals::GetAdditionalSynthetics ()
46 {
47     static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> g_map;
48     return g_map;
49 }
50 
51 static CompilerType
52 GetLLDBNSPairType (TargetSP target_sp)
53 {
54     CompilerType compiler_type;
55 
56     ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext();
57 
58     if (target_ast_context)
59     {
60         ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
61 
62         compiler_type = target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(g___lldb_autogen_nspair);
63 
64         if (!compiler_type)
65         {
66             compiler_type = target_ast_context->CreateRecordType(nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct, lldb::eLanguageTypeC);
67 
68             if (compiler_type)
69             {
70                 ClangASTContext::StartTagDeclarationDefinition(compiler_type);
71                 CompilerType id_compiler_type = target_ast_context->GetBasicType (eBasicTypeObjCID);
72                 ClangASTContext::AddFieldToRecordType(compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
73                 ClangASTContext::AddFieldToRecordType(compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
74                 ClangASTContext::CompleteTagDeclarationDefinition(compiler_type);
75             }
76         }
77     }
78     return compiler_type;
79 }
80 
81 namespace lldb_private {
82     namespace  formatters {
83         class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd
84         {
85         public:
86             NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
87 
88             ~NSDictionaryISyntheticFrontEnd() override;
89 
90             size_t
91             CalculateNumChildren() override;
92 
93             lldb::ValueObjectSP
94             GetChildAtIndex(size_t idx) override;
95 
96             bool
97             Update() override;
98 
99             bool
100             MightHaveChildren() override;
101 
102             size_t
103             GetIndexOfChildWithName(const ConstString &name) override;
104 
105         private:
106             struct DataDescriptor_32
107             {
108                 uint32_t _used : 26;
109                 uint32_t _szidx : 6;
110             };
111 
112             struct DataDescriptor_64
113             {
114                 uint64_t _used : 58;
115                 uint32_t _szidx : 6;
116             };
117 
118             struct DictionaryItemDescriptor
119             {
120                 lldb::addr_t key_ptr;
121                 lldb::addr_t val_ptr;
122                 lldb::ValueObjectSP valobj_sp;
123             };
124 
125             ExecutionContextRef m_exe_ctx_ref;
126             uint8_t m_ptr_size;
127             lldb::ByteOrder m_order;
128             DataDescriptor_32 *m_data_32;
129             DataDescriptor_64 *m_data_64;
130             lldb::addr_t m_data_ptr;
131             CompilerType m_pair_type;
132             std::vector<DictionaryItemDescriptor> m_children;
133         };
134 
135         class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd
136         {
137         public:
138             NSDictionary1SyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
139 
140             ~NSDictionary1SyntheticFrontEnd() override = default;
141 
142             size_t
143             CalculateNumChildren() override;
144 
145             lldb::ValueObjectSP
146             GetChildAtIndex(size_t idx) override;
147 
148             bool
149             Update() override;
150 
151             bool
152             MightHaveChildren() override;
153 
154             size_t
155             GetIndexOfChildWithName(const ConstString &name) override;
156 
157         private:
158             ValueObjectSP m_pair;
159         };
160 
161         class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
162         {
163         public:
164             NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
165 
166             ~NSDictionaryMSyntheticFrontEnd() override;
167 
168             size_t
169             CalculateNumChildren() override;
170 
171             lldb::ValueObjectSP
172             GetChildAtIndex(size_t idx) override;
173 
174             bool
175             Update() override;
176 
177             bool
178             MightHaveChildren() override;
179 
180             size_t
181             GetIndexOfChildWithName(const ConstString &name) override;
182 
183         private:
184             struct DataDescriptor_32
185             {
186                 uint32_t _used : 26;
187                 uint32_t _kvo : 1;
188                 uint32_t _size;
189                 uint32_t _mutations;
190                 uint32_t _objs_addr;
191                 uint32_t _keys_addr;
192             };
193 
194             struct DataDescriptor_64
195             {
196                 uint64_t _used : 58;
197                 uint32_t _kvo : 1;
198                 uint64_t _size;
199                 uint64_t _mutations;
200                 uint64_t _objs_addr;
201                 uint64_t _keys_addr;
202             };
203 
204             struct DictionaryItemDescriptor
205             {
206                 lldb::addr_t key_ptr;
207                 lldb::addr_t val_ptr;
208                 lldb::ValueObjectSP valobj_sp;
209             };
210 
211             ExecutionContextRef m_exe_ctx_ref;
212             uint8_t m_ptr_size;
213             lldb::ByteOrder m_order;
214             DataDescriptor_32 *m_data_32;
215             DataDescriptor_64 *m_data_64;
216             CompilerType m_pair_type;
217             std::vector<DictionaryItemDescriptor> m_children;
218         };
219     } // namespace formatters
220 } // namespace lldb_private
221 
222 template<bool name_entries>
223 bool
224 lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
225 {
226     static ConstString g_TypeHint("NSDictionary");
227     ProcessSP process_sp = valobj.GetProcessSP();
228     if (!process_sp)
229         return false;
230 
231     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
232 
233     if (!runtime)
234         return false;
235 
236     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
237 
238     if (!descriptor || !descriptor->IsValid())
239         return false;
240 
241     uint32_t ptr_size = process_sp->GetAddressByteSize();
242     bool is_64bit = (ptr_size == 8);
243 
244     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
245 
246     if (!valobj_addr)
247         return false;
248 
249     uint64_t value = 0;
250 
251     ConstString class_name(descriptor->GetClassName());
252 
253     static const ConstString g_DictionaryI("__NSDictionaryI");
254     static const ConstString g_DictionaryM("__NSDictionaryM");
255     static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
256 
257     if (class_name.IsEmpty())
258         return false;
259 
260     if (class_name == g_DictionaryI)
261     {
262         Error error;
263         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
264         if (error.Fail())
265             return false;
266         value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
267     }
268     else if (class_name == g_DictionaryM)
269     {
270         Error error;
271         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
272         if (error.Fail())
273             return false;
274         value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
275     }
276     else if (class_name == g_Dictionary1)
277     {
278         value = 1;
279     }
280     /*else if (!strcmp(class_name,"__NSCFDictionary"))
281      {
282      Error error;
283      value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
284      if (error.Fail())
285      return false;
286      if (is_64bit)
287      value &= ~0x0f1f000000000000UL;
288      }*/
289     else
290     {
291         auto& map(NSDictionary_Additionals::GetAdditionalSummaries());
292         auto iter = map.find(class_name), end = map.end();
293         if (iter != end)
294             return iter->second(valobj, stream, options);
295         else
296             return false;
297     }
298 
299     std::string prefix,suffix;
300     if (Language* language = Language::FindPlugin(options.GetLanguage()))
301     {
302         if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
303         {
304             prefix.clear();
305             suffix.clear();
306         }
307     }
308 
309     stream.Printf("%s%" PRIu64 " %s%s%s",
310                   prefix.c_str(),
311                   value,
312                   "key/value pair",
313                   value == 1 ? "" : "s",
314                   suffix.c_str());
315     return true;
316 }
317 
318 SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren* synth, lldb::ValueObjectSP valobj_sp)
319 {
320     lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
321     if (!process_sp)
322         return nullptr;
323     ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
324     if (!runtime)
325         return nullptr;
326 
327     CompilerType valobj_type(valobj_sp->GetCompilerType());
328     Flags flags(valobj_type.GetTypeInfo());
329 
330     if (flags.IsClear(eTypeIsPointer))
331     {
332         Error error;
333         valobj_sp = valobj_sp->AddressOf(error);
334         if (error.Fail() || !valobj_sp)
335             return nullptr;
336     }
337 
338     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp));
339 
340     if (!descriptor || !descriptor->IsValid())
341         return nullptr;
342 
343     ConstString class_name(descriptor->GetClassName());
344 
345     static const ConstString g_DictionaryI("__NSDictionaryI");
346     static const ConstString g_DictionaryM("__NSDictionaryM");
347     static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
348 
349     if (class_name.IsEmpty())
350         return nullptr;
351 
352     if (class_name == g_DictionaryI)
353     {
354         return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
355     }
356     else if (class_name == g_DictionaryM)
357     {
358         return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
359     }
360     else if (class_name == g_Dictionary1)
361     {
362         return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
363     }
364     else
365     {
366         auto& map(NSDictionary_Additionals::GetAdditionalSynthetics());
367         auto iter = map.find(class_name), end = map.end();
368         if (iter != end)
369             return iter->second(synth, valobj_sp);
370     }
371 
372     return nullptr;
373 }
374 
375 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
376     SyntheticChildrenFrontEnd(*valobj_sp),
377     m_exe_ctx_ref(),
378     m_ptr_size(8),
379     m_order(lldb::eByteOrderInvalid),
380     m_data_32(nullptr),
381     m_data_64(nullptr),
382     m_pair_type()
383 {
384 }
385 
386 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd ()
387 {
388     delete m_data_32;
389     m_data_32 = nullptr;
390     delete m_data_64;
391     m_data_64 = nullptr;
392 }
393 
394 size_t
395 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
396 {
397     const char* item_name = name.GetCString();
398     uint32_t idx = ExtractIndexFromString(item_name);
399     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
400         return UINT32_MAX;
401     return idx;
402 }
403 
404 size_t
405 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren ()
406 {
407     if (!m_data_32 && !m_data_64)
408         return 0;
409     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
410 }
411 
412 bool
413 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
414 {
415     m_children.clear();
416     delete m_data_32;
417     m_data_32 = nullptr;
418     delete m_data_64;
419     m_data_64 = nullptr;
420     m_ptr_size = 0;
421     ValueObjectSP valobj_sp = m_backend.GetSP();
422     if (!valobj_sp)
423         return false;
424     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
425     Error error;
426     error.Clear();
427     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
428     if (!process_sp)
429         return false;
430     m_ptr_size = process_sp->GetAddressByteSize();
431     m_order = process_sp->GetByteOrder();
432     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
433     if (m_ptr_size == 4)
434     {
435         m_data_32 = new DataDescriptor_32();
436         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
437     }
438     else
439     {
440         m_data_64 = new DataDescriptor_64();
441         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
442     }
443     if (error.Fail())
444         return false;
445     m_data_ptr = data_location + m_ptr_size;
446     return false;
447 }
448 
449 bool
450 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren ()
451 {
452     return true;
453 }
454 
455 lldb::ValueObjectSP
456 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx)
457 {
458     uint32_t num_children = CalculateNumChildren();
459 
460     if (idx >= num_children)
461         return lldb::ValueObjectSP();
462 
463     if (m_children.empty())
464     {
465         // do the scan phase
466         lldb::addr_t key_at_idx = 0, val_at_idx = 0;
467 
468         uint32_t tries = 0;
469         uint32_t test_idx = 0;
470 
471         while(tries < num_children)
472         {
473             key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size);
474             val_at_idx = key_at_idx + m_ptr_size;
475             ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
476             if (!process_sp)
477                 return lldb::ValueObjectSP();
478             Error error;
479             key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
480             if (error.Fail())
481                 return lldb::ValueObjectSP();
482             val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
483             if (error.Fail())
484                 return lldb::ValueObjectSP();
485 
486             test_idx++;
487 
488             if (!key_at_idx || !val_at_idx)
489                 continue;
490             tries++;
491 
492             DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
493 
494             m_children.push_back(descriptor);
495         }
496     }
497 
498     if (idx >= m_children.size()) // should never happen
499         return lldb::ValueObjectSP();
500 
501     DictionaryItemDescriptor &dict_item = m_children[idx];
502     if (!dict_item.valobj_sp)
503     {
504         if (!m_pair_type.IsValid())
505         {
506             TargetSP target_sp(m_backend.GetTargetSP());
507             if (!target_sp)
508                 return ValueObjectSP();
509             m_pair_type = GetLLDBNSPairType(target_sp);
510         }
511         if (!m_pair_type.IsValid())
512             return ValueObjectSP();
513 
514         DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
515 
516         if (m_ptr_size == 8)
517         {
518             uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
519             *data_ptr = dict_item.key_ptr;
520             *(data_ptr+1) = dict_item.val_ptr;
521         }
522         else
523         {
524             uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
525             *data_ptr = dict_item.key_ptr;
526             *(data_ptr+1) = dict_item.val_ptr;
527         }
528 
529         StreamString idx_name;
530         idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
531         DataExtractor data(buffer_sp, m_order, m_ptr_size);
532         dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(),
533                                                         data,
534                                                         m_exe_ctx_ref,
535                                                         m_pair_type);
536     }
537     return dict_item.valobj_sp;
538 }
539 
540 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::NSDictionary1SyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
541 SyntheticChildrenFrontEnd(*valobj_sp.get()),
542 m_pair(nullptr)
543 {
544 }
545 
546 size_t
547 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
548 {
549     static const ConstString g_zero("[0]");
550 
551     if (name == g_zero)
552         return 0;
553 
554     return UINT32_MAX;
555 }
556 
557 size_t
558 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::CalculateNumChildren ()
559 {
560     return 1;
561 }
562 
563 bool
564 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update()
565 {
566     m_pair.reset();
567     return false;
568 }
569 
570 bool
571 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::MightHaveChildren ()
572 {
573     return true;
574 }
575 
576 lldb::ValueObjectSP
577 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex (size_t idx)
578 {
579     if (idx != 0)
580         return lldb::ValueObjectSP();
581 
582     if (m_pair.get())
583         return m_pair;
584 
585     auto process_sp(m_backend.GetProcessSP());
586     if (!process_sp)
587         return nullptr;
588 
589     auto ptr_size = process_sp->GetAddressByteSize();
590 
591     lldb::addr_t key_ptr = m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
592     lldb::addr_t value_ptr = key_ptr + ptr_size;
593 
594     Error error;
595 
596     lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
597     if (error.Fail())
598         return nullptr;
599     lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
600     if (error.Fail())
601         return nullptr;
602 
603     auto pair_type = GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
604 
605     DataBufferSP buffer_sp(new DataBufferHeap(2*ptr_size,0));
606 
607     if (ptr_size == 8)
608     {
609         uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
610         *data_ptr = key_at_idx;
611         *(data_ptr+1) = value_at_idx;
612     }
613     else
614     {
615         uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
616         *data_ptr = key_ptr;
617         *(data_ptr+1) = value_ptr;
618     }
619 
620     DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
621     m_pair = CreateValueObjectFromData("[0]",
622                                        data,
623                                        m_backend.GetExecutionContextRef(),
624                                        pair_type);
625 
626 
627     return m_pair;
628 }
629 
630 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
631     SyntheticChildrenFrontEnd(*valobj_sp),
632     m_exe_ctx_ref(),
633     m_ptr_size(8),
634     m_order(lldb::eByteOrderInvalid),
635     m_data_32(nullptr),
636     m_data_64(nullptr),
637     m_pair_type()
638 {
639 }
640 
641 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd ()
642 {
643     delete m_data_32;
644     m_data_32 = nullptr;
645     delete m_data_64;
646     m_data_64 = nullptr;
647 }
648 
649 size_t
650 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
651 {
652     const char* item_name = name.GetCString();
653     uint32_t idx = ExtractIndexFromString(item_name);
654     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
655         return UINT32_MAX;
656     return idx;
657 }
658 
659 size_t
660 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren ()
661 {
662     if (!m_data_32 && !m_data_64)
663         return 0;
664     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
665 }
666 
667 bool
668 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
669 {
670     m_children.clear();
671     ValueObjectSP valobj_sp = m_backend.GetSP();
672     m_ptr_size = 0;
673     delete m_data_32;
674     m_data_32 = nullptr;
675     delete m_data_64;
676     m_data_64 = nullptr;
677     if (!valobj_sp)
678         return false;
679     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
680     Error error;
681     error.Clear();
682     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
683     if (!process_sp)
684         return false;
685     m_ptr_size = process_sp->GetAddressByteSize();
686     m_order = process_sp->GetByteOrder();
687     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
688     if (m_ptr_size == 4)
689     {
690         m_data_32 = new DataDescriptor_32();
691         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
692     }
693     else
694     {
695         m_data_64 = new DataDescriptor_64();
696         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
697     }
698     if (error.Fail())
699         return false;
700     return false;
701 }
702 
703 bool
704 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren ()
705 {
706     return true;
707 }
708 
709 lldb::ValueObjectSP
710 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
711 {
712     lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
713     lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
714 
715     uint32_t num_children = CalculateNumChildren();
716 
717     if (idx >= num_children)
718         return lldb::ValueObjectSP();
719 
720     if (m_children.empty())
721     {
722         // do the scan phase
723         lldb::addr_t key_at_idx = 0, val_at_idx = 0;
724 
725         uint32_t tries = 0;
726         uint32_t test_idx = 0;
727 
728         while(tries < num_children)
729         {
730             key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
731             val_at_idx = m_values_ptr + (test_idx * m_ptr_size);;
732             ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
733             if (!process_sp)
734                 return lldb::ValueObjectSP();
735             Error error;
736             key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
737             if (error.Fail())
738                 return lldb::ValueObjectSP();
739             val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
740             if (error.Fail())
741                 return lldb::ValueObjectSP();
742 
743             test_idx++;
744 
745             if (!key_at_idx || !val_at_idx)
746                 continue;
747             tries++;
748 
749             DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
750 
751             m_children.push_back(descriptor);
752         }
753     }
754 
755     if (idx >= m_children.size()) // should never happen
756         return lldb::ValueObjectSP();
757 
758     DictionaryItemDescriptor &dict_item = m_children[idx];
759     if (!dict_item.valobj_sp)
760     {
761         if (!m_pair_type.IsValid())
762         {
763             TargetSP target_sp(m_backend.GetTargetSP());
764             if (!target_sp)
765                 return ValueObjectSP();
766             m_pair_type = GetLLDBNSPairType(target_sp);
767         }
768         if (!m_pair_type.IsValid())
769             return ValueObjectSP();
770 
771         DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
772 
773         if (m_ptr_size == 8)
774         {
775             uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
776             *data_ptr = dict_item.key_ptr;
777             *(data_ptr+1) = dict_item.val_ptr;
778         }
779         else
780         {
781             uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
782             *data_ptr = dict_item.key_ptr;
783             *(data_ptr+1) = dict_item.val_ptr;
784         }
785 
786         StreamString idx_name;
787         idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
788         DataExtractor data(buffer_sp, m_order, m_ptr_size);
789         dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(),
790                                                         data,
791                                                         m_exe_ctx_ref,
792                                                         m_pair_type);
793     }
794     return dict_item.valobj_sp;
795 }
796 
797 template bool
798 lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&);
799 
800 template bool
801 lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&);
802