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