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 <mutex>
11 
12 #include "clang/AST/DeclCXX.h"
13 
14 #include "NSDictionary.h"
15 
16 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
17 
18 #include "lldb/Core/ValueObject.h"
19 #include "lldb/Core/ValueObjectConstResult.h"
20 #include "lldb/DataFormatters/FormattersHelpers.h"
21 #include "lldb/Symbol/ClangASTContext.h"
22 #include "lldb/Target/Language.h"
23 #include "lldb/Target/ObjCLanguageRuntime.h"
24 #include "lldb/Target/StackFrame.h"
25 #include "lldb/Target/Target.h"
26 #include "lldb/Utility/DataBufferHeap.h"
27 #include "lldb/Utility/Endian.h"
28 #include "lldb/Utility/Status.h"
29 #include "lldb/Utility/Stream.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 using namespace lldb_private::formatters;
34 
35 NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
36     ConstString p)
37     : m_prefix(p) {}
38 
39 bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(
40     ConstString class_name) {
41   return class_name.GetStringRef().startswith(m_prefix.GetStringRef());
42 }
43 
44 NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)
45     : m_name(n) {}
46 
47 bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match(
48     ConstString class_name) {
49   return (class_name == m_name);
50 }
51 
52 NSDictionary_Additionals::AdditionalFormatters<
53     CXXFunctionSummaryFormat::Callback> &
54 NSDictionary_Additionals::GetAdditionalSummaries() {
55   static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map;
56   return g_map;
57 }
58 
59 NSDictionary_Additionals::AdditionalFormatters<
60     CXXSyntheticChildren::CreateFrontEndCallback> &
61 NSDictionary_Additionals::GetAdditionalSynthetics() {
62   static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback>
63       g_map;
64   return g_map;
65 }
66 
67 static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
68   CompilerType compiler_type;
69 
70   ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext();
71 
72   if (target_ast_context) {
73     ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
74 
75     compiler_type =
76         target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(
77             g___lldb_autogen_nspair);
78 
79     if (!compiler_type) {
80       compiler_type = target_ast_context->CreateRecordType(
81           nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(),
82           clang::TTK_Struct, lldb::eLanguageTypeC);
83 
84       if (compiler_type) {
85         ClangASTContext::StartTagDeclarationDefinition(compiler_type);
86         CompilerType id_compiler_type =
87             target_ast_context->GetBasicType(eBasicTypeObjCID);
88         ClangASTContext::AddFieldToRecordType(
89             compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
90         ClangASTContext::AddFieldToRecordType(
91             compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
92         ClangASTContext::CompleteTagDeclarationDefinition(compiler_type);
93       }
94     }
95   }
96   return compiler_type;
97 }
98 
99 namespace lldb_private {
100 namespace formatters {
101 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
102 public:
103   NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
104 
105   ~NSDictionaryISyntheticFrontEnd() override;
106 
107   size_t CalculateNumChildren() override;
108 
109   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
110 
111   bool Update() override;
112 
113   bool MightHaveChildren() override;
114 
115   size_t GetIndexOfChildWithName(const ConstString &name) override;
116 
117 private:
118   struct DataDescriptor_32 {
119     uint32_t _used : 26;
120     uint32_t _szidx : 6;
121   };
122 
123   struct DataDescriptor_64 {
124     uint64_t _used : 58;
125     uint32_t _szidx : 6;
126   };
127 
128   struct DictionaryItemDescriptor {
129     lldb::addr_t key_ptr;
130     lldb::addr_t val_ptr;
131     lldb::ValueObjectSP valobj_sp;
132   };
133 
134   ExecutionContextRef m_exe_ctx_ref;
135   uint8_t m_ptr_size;
136   lldb::ByteOrder m_order;
137   DataDescriptor_32 *m_data_32;
138   DataDescriptor_64 *m_data_64;
139   lldb::addr_t m_data_ptr;
140   CompilerType m_pair_type;
141   std::vector<DictionaryItemDescriptor> m_children;
142 };
143 
144 class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
145 public:
146   NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
147 
148   ~NSDictionary1SyntheticFrontEnd() override = default;
149 
150   size_t CalculateNumChildren() override;
151 
152   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
153 
154   bool Update() override;
155 
156   bool MightHaveChildren() override;
157 
158   size_t GetIndexOfChildWithName(const ConstString &name) override;
159 
160 private:
161   ValueObjectSP m_pair;
162 };
163 
164 template <typename D32, typename D64>
165 class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
166 public:
167   GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
168 
169   ~GenericNSDictionaryMSyntheticFrontEnd() override;
170 
171   size_t CalculateNumChildren() override;
172 
173   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
174 
175   bool Update() override;
176 
177   bool MightHaveChildren() override;
178 
179   size_t GetIndexOfChildWithName(const ConstString &name) override;
180 
181 private:
182   struct DictionaryItemDescriptor {
183     lldb::addr_t key_ptr;
184     lldb::addr_t val_ptr;
185     lldb::ValueObjectSP valobj_sp;
186   };
187 
188   ExecutionContextRef m_exe_ctx_ref;
189   uint8_t m_ptr_size;
190   lldb::ByteOrder m_order;
191   D32 *m_data_32;
192   D64 *m_data_64;
193   CompilerType m_pair_type;
194   std::vector<DictionaryItemDescriptor> m_children;
195 };
196 
197 namespace Foundation1100 {
198   class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
199   public:
200     NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
201 
202     ~NSDictionaryMSyntheticFrontEnd() override;
203 
204     size_t CalculateNumChildren() override;
205 
206     lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
207 
208     bool Update() override;
209 
210     bool MightHaveChildren() override;
211 
212     size_t GetIndexOfChildWithName(const ConstString &name) override;
213 
214   private:
215     struct DataDescriptor_32 {
216       uint32_t _used : 26;
217       uint32_t _kvo : 1;
218       uint32_t _size;
219       uint32_t _mutations;
220       uint32_t _objs_addr;
221       uint32_t _keys_addr;
222     };
223 
224     struct DataDescriptor_64 {
225       uint64_t _used : 58;
226       uint32_t _kvo : 1;
227       uint64_t _size;
228       uint64_t _mutations;
229       uint64_t _objs_addr;
230       uint64_t _keys_addr;
231     };
232 
233     struct DictionaryItemDescriptor {
234       lldb::addr_t key_ptr;
235       lldb::addr_t val_ptr;
236       lldb::ValueObjectSP valobj_sp;
237     };
238 
239     ExecutionContextRef m_exe_ctx_ref;
240     uint8_t m_ptr_size;
241     lldb::ByteOrder m_order;
242     DataDescriptor_32 *m_data_32;
243     DataDescriptor_64 *m_data_64;
244     CompilerType m_pair_type;
245     std::vector<DictionaryItemDescriptor> m_children;
246   };
247 }
248 
249 namespace Foundation1428 {
250   struct DataDescriptor_32 {
251     uint32_t _used : 26;
252     uint32_t _kvo : 1;
253     uint32_t _size;
254     uint32_t _buffer;
255     uint64_t GetSize() { return _size; }
256   };
257 
258   struct DataDescriptor_64 {
259     uint64_t _used : 58;
260     uint32_t _kvo : 1;
261     uint64_t _size;
262     uint64_t _buffer;
263     uint64_t GetSize() { return _size; }
264   };
265 
266 
267 
268   using NSDictionaryMSyntheticFrontEnd =
269     GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
270 }
271 
272 namespace Foundation1437 {
273   static const uint64_t NSDictionaryCapacities[] = {
274       0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
275       2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
276       214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
277       6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
278       111638519, 180634607, 292272623, 472907251
279   };
280 
281   static const size_t NSDictionaryNumSizeBuckets = sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
282 
283   struct DataDescriptor_32 {
284     uint32_t _buffer;
285     union {
286       struct {
287         uint32_t _mutations;
288       };
289       struct {
290         uint32_t _muts;
291         uint32_t _used:25;
292         uint32_t _kvo:1;
293         uint32_t _szidx:6;
294       };
295     };
296 
297     uint64_t GetSize() {
298       return (_szidx) >= NSDictionaryNumSizeBuckets ?
299           0 : NSDictionaryCapacities[_szidx];
300     }
301   };
302 
303   struct DataDescriptor_64 {
304     uint64_t _buffer;
305     union {
306       struct {
307         uint64_t _mutations;
308       };
309       struct {
310         uint32_t _muts;
311         uint32_t _used:25;
312         uint32_t _kvo:1;
313         uint32_t _szidx:6;
314       };
315     };
316 
317     uint64_t GetSize() {
318       return (_szidx) >= NSDictionaryNumSizeBuckets ?
319           0 : NSDictionaryCapacities[_szidx];
320     }
321   };
322 
323   using NSDictionaryMSyntheticFrontEnd =
324     GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
325 
326   template <typename DD>
327   uint64_t
328   __NSDictionaryMSize_Impl(lldb_private::Process &process,
329                            lldb::addr_t valobj_addr, Status &error) {
330     const lldb::addr_t start_of_descriptor =
331         valobj_addr + process.GetAddressByteSize();
332     DD descriptor = DD();
333     process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
334                        error);
335     if (error.Fail()) {
336       return 0;
337     }
338     return descriptor._used;
339   }
340 
341   uint64_t
342   __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
343                Status &error) {
344     if (process.GetAddressByteSize() == 4) {
345       return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
346                                                          error);
347     } else {
348       return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
349                                                          error);
350     }
351   }
352 
353 }
354 } // namespace formatters
355 } // namespace lldb_private
356 
357 template <bool name_entries>
358 bool lldb_private::formatters::NSDictionarySummaryProvider(
359     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
360   static ConstString g_TypeHint("NSDictionary");
361   ProcessSP process_sp = valobj.GetProcessSP();
362   if (!process_sp)
363     return false;
364 
365   ObjCLanguageRuntime *runtime =
366       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
367           lldb::eLanguageTypeObjC);
368 
369   if (!runtime)
370     return false;
371 
372   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
373       runtime->GetClassDescriptor(valobj));
374 
375   if (!descriptor || !descriptor->IsValid())
376     return false;
377 
378   uint32_t ptr_size = process_sp->GetAddressByteSize();
379   bool is_64bit = (ptr_size == 8);
380 
381   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
382 
383   if (!valobj_addr)
384     return false;
385 
386   uint64_t value = 0;
387 
388   ConstString class_name(descriptor->GetClassName());
389 
390   static const ConstString g_DictionaryI("__NSDictionaryI");
391   static const ConstString g_DictionaryM("__NSDictionaryM");
392   static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
393   static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
394   static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
395   static const ConstString g_Dictionary0("__NSDictionary0");
396   static const ConstString g_DictionaryCF("__NSCFDictionary");
397 
398   if (class_name.IsEmpty())
399     return false;
400 
401   if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
402     Status error;
403     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
404                                                       ptr_size, 0, error);
405     if (error.Fail())
406       return false;
407     value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
408   } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
409              class_name == g_DictionaryCF) {
410     AppleObjCRuntime *apple_runtime =
411     llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
412     Status error;
413     if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
414       value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
415                                                   error);
416     } else {
417       value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
418                                                         ptr_size, 0, error);
419       value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
420     }
421     if (error.Fail())
422       return false;
423   } else if (class_name == g_Dictionary1) {
424     value = 1;
425   } else if (class_name == g_Dictionary0) {
426     value = 0;
427   }
428   else {
429     auto &map(NSDictionary_Additionals::GetAdditionalSummaries());
430     for (auto &candidate : map) {
431       if (candidate.first && candidate.first->Match(class_name))
432         return candidate.second(valobj, stream, options);
433     }
434     return false;
435   }
436 
437   std::string prefix, suffix;
438   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
439     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
440                                             suffix)) {
441       prefix.clear();
442       suffix.clear();
443     }
444   }
445 
446   stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair",
447                 value == 1 ? "" : "s", suffix.c_str());
448   return true;
449 }
450 
451 SyntheticChildrenFrontEnd *
452 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
453     CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
454   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
455   if (!process_sp)
456     return nullptr;
457   AppleObjCRuntime *runtime =
458       llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
459   if (!runtime)
460     return nullptr;
461 
462   CompilerType valobj_type(valobj_sp->GetCompilerType());
463   Flags flags(valobj_type.GetTypeInfo());
464 
465   if (flags.IsClear(eTypeIsPointer)) {
466     Status error;
467     valobj_sp = valobj_sp->AddressOf(error);
468     if (error.Fail() || !valobj_sp)
469       return nullptr;
470   }
471 
472   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
473       runtime->GetClassDescriptor(*valobj_sp));
474 
475   if (!descriptor || !descriptor->IsValid())
476     return nullptr;
477 
478   ConstString class_name(descriptor->GetClassName());
479 
480   static const ConstString g_DictionaryI("__NSDictionaryI");
481   static const ConstString g_DictionaryM("__NSDictionaryM");
482   static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
483   static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
484   static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
485   static const ConstString g_Dictionary0("__NSDictionary0");
486 
487   if (class_name.IsEmpty())
488     return nullptr;
489 
490   if (class_name == g_DictionaryI) {
491     return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
492   } else if (class_name == g_DictionaryM) {
493     if (runtime->GetFoundationVersion() >= 1437) {
494       return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
495     } else if (runtime->GetFoundationVersion() >= 1428) {
496       return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));
497     } else {
498       return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
499     }
500   } else if (class_name == g_DictionaryMLegacy) {
501       return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
502   } else if (class_name == g_Dictionary1) {
503     return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
504   } else {
505     auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());
506     for (auto &candidate : map) {
507       if (candidate.first && candidate.first->Match((class_name)))
508         return candidate.second(synth, valobj_sp);
509     }
510   }
511 
512   return nullptr;
513 }
514 
515 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
516     NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
517     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
518       m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
519       m_pair_type() {}
520 
521 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
522     ~NSDictionaryISyntheticFrontEnd() {
523   delete m_data_32;
524   m_data_32 = nullptr;
525   delete m_data_64;
526   m_data_64 = nullptr;
527 }
528 
529 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
530     GetIndexOfChildWithName(const ConstString &name) {
531   const char *item_name = name.GetCString();
532   uint32_t idx = ExtractIndexFromString(item_name);
533   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
534     return UINT32_MAX;
535   return idx;
536 }
537 
538 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
539     CalculateNumChildren() {
540   if (!m_data_32 && !m_data_64)
541     return 0;
542   return (m_data_32 ? m_data_32->_used : m_data_64->_used);
543 }
544 
545 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
546   m_children.clear();
547   delete m_data_32;
548   m_data_32 = nullptr;
549   delete m_data_64;
550   m_data_64 = nullptr;
551   m_ptr_size = 0;
552   ValueObjectSP valobj_sp = m_backend.GetSP();
553   if (!valobj_sp)
554     return false;
555   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
556   Status error;
557   error.Clear();
558   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
559   if (!process_sp)
560     return false;
561   m_ptr_size = process_sp->GetAddressByteSize();
562   m_order = process_sp->GetByteOrder();
563   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
564   if (m_ptr_size == 4) {
565     m_data_32 = new DataDescriptor_32();
566     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
567                            error);
568   } else {
569     m_data_64 = new DataDescriptor_64();
570     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
571                            error);
572   }
573   if (error.Fail())
574     return false;
575   m_data_ptr = data_location + m_ptr_size;
576   return false;
577 }
578 
579 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
580     MightHaveChildren() {
581   return true;
582 }
583 
584 lldb::ValueObjectSP
585 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
586     size_t idx) {
587   uint32_t num_children = CalculateNumChildren();
588 
589   if (idx >= num_children)
590     return lldb::ValueObjectSP();
591 
592   if (m_children.empty()) {
593     // do the scan phase
594     lldb::addr_t key_at_idx = 0, val_at_idx = 0;
595 
596     uint32_t tries = 0;
597     uint32_t test_idx = 0;
598 
599     while (tries < num_children) {
600       key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
601       val_at_idx = key_at_idx + m_ptr_size;
602       ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
603       if (!process_sp)
604         return lldb::ValueObjectSP();
605       Status error;
606       key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
607       if (error.Fail())
608         return lldb::ValueObjectSP();
609       val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
610       if (error.Fail())
611         return lldb::ValueObjectSP();
612 
613       test_idx++;
614 
615       if (!key_at_idx || !val_at_idx)
616         continue;
617       tries++;
618 
619       DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
620                                              lldb::ValueObjectSP()};
621 
622       m_children.push_back(descriptor);
623     }
624   }
625 
626   if (idx >= m_children.size()) // should never happen
627     return lldb::ValueObjectSP();
628 
629   DictionaryItemDescriptor &dict_item = m_children[idx];
630   if (!dict_item.valobj_sp) {
631     if (!m_pair_type.IsValid()) {
632       TargetSP target_sp(m_backend.GetTargetSP());
633       if (!target_sp)
634         return ValueObjectSP();
635       m_pair_type = GetLLDBNSPairType(target_sp);
636     }
637     if (!m_pair_type.IsValid())
638       return ValueObjectSP();
639 
640     DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
641 
642     if (m_ptr_size == 8) {
643       uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
644       *data_ptr = dict_item.key_ptr;
645       *(data_ptr + 1) = dict_item.val_ptr;
646     } else {
647       uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
648       *data_ptr = dict_item.key_ptr;
649       *(data_ptr + 1) = dict_item.val_ptr;
650     }
651 
652     StreamString idx_name;
653     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
654     DataExtractor data(buffer_sp, m_order, m_ptr_size);
655     dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
656                                                     m_exe_ctx_ref, m_pair_type);
657   }
658   return dict_item.valobj_sp;
659 }
660 
661 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
662     NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
663     : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
664 
665 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
666     GetIndexOfChildWithName(const ConstString &name) {
667   static const ConstString g_zero("[0]");
668   return name == g_zero ? 0 : UINT32_MAX;
669 }
670 
671 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
672     CalculateNumChildren() {
673   return 1;
674 }
675 
676 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
677   m_pair.reset();
678   return false;
679 }
680 
681 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
682     MightHaveChildren() {
683   return true;
684 }
685 
686 lldb::ValueObjectSP
687 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
688     size_t idx) {
689   if (idx != 0)
690     return lldb::ValueObjectSP();
691 
692   if (m_pair.get())
693     return m_pair;
694 
695   auto process_sp(m_backend.GetProcessSP());
696   if (!process_sp)
697     return nullptr;
698 
699   auto ptr_size = process_sp->GetAddressByteSize();
700 
701   lldb::addr_t key_ptr =
702       m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
703   lldb::addr_t value_ptr = key_ptr + ptr_size;
704 
705   Status error;
706 
707   lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
708   if (error.Fail())
709     return nullptr;
710   lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
711   if (error.Fail())
712     return nullptr;
713 
714   auto pair_type =
715       GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
716 
717   DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
718 
719   if (ptr_size == 8) {
720     uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
721     *data_ptr = key_at_idx;
722     *(data_ptr + 1) = value_at_idx;
723   } else {
724     uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
725     *data_ptr = key_at_idx;
726     *(data_ptr + 1) = value_at_idx;
727   }
728 
729   DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
730   m_pair = CreateValueObjectFromData(
731       "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
732 
733   return m_pair;
734 }
735 
736 template <typename D32, typename D64>
737 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
738     GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
739     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
740       m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
741       m_pair_type() {}
742 
743 template <typename D32, typename D64>
744 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
745     ~GenericNSDictionaryMSyntheticFrontEnd() {
746   delete m_data_32;
747   m_data_32 = nullptr;
748   delete m_data_64;
749   m_data_64 = nullptr;
750 }
751 
752 template <typename D32, typename D64>
753 size_t
754 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::    GetIndexOfChildWithName(const ConstString &name) {
755   const char *item_name = name.GetCString();
756   uint32_t idx = ExtractIndexFromString(item_name);
757   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
758     return UINT32_MAX;
759   return idx;
760 }
761 
762 template <typename D32, typename D64>
763 size_t
764 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() {
765   if (!m_data_32 && !m_data_64)
766     return 0;
767   return (m_data_32 ? m_data_32->_used : m_data_64->_used);
768 }
769 
770 template <typename D32, typename D64>
771 bool
772 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
773   Update() {
774   m_children.clear();
775   ValueObjectSP valobj_sp = m_backend.GetSP();
776   m_ptr_size = 0;
777   delete m_data_32;
778   m_data_32 = nullptr;
779   delete m_data_64;
780   m_data_64 = nullptr;
781   if (!valobj_sp)
782     return false;
783   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
784   Status error;
785   error.Clear();
786   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
787   if (!process_sp)
788     return false;
789   m_ptr_size = process_sp->GetAddressByteSize();
790   m_order = process_sp->GetByteOrder();
791   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
792   if (m_ptr_size == 4) {
793     m_data_32 = new D32();
794     process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
795                            error);
796   } else {
797     m_data_64 = new D64();
798     process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
799                            error);
800   }
801   if (error.Fail())
802     return false;
803   return false;
804 }
805 
806 template <typename D32, typename D64>
807 bool
808 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
809     MightHaveChildren() {
810   return true;
811 }
812 
813 template <typename D32, typename D64>
814 lldb::ValueObjectSP
815 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
816     GetChildAtIndex(
817     size_t idx) {
818   lldb::addr_t m_keys_ptr;
819   lldb::addr_t m_values_ptr;
820   if (m_data_32) {
821     uint32_t size = m_data_32->GetSize();
822     m_keys_ptr = m_data_32->_buffer;
823     m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
824   } else {
825     uint32_t size = m_data_64->GetSize();
826     m_keys_ptr = m_data_64->_buffer;
827     m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
828   }
829 
830   uint32_t num_children = CalculateNumChildren();
831 
832   if (idx >= num_children)
833     return lldb::ValueObjectSP();
834 
835   if (m_children.empty()) {
836     // do the scan phase
837     lldb::addr_t key_at_idx = 0, val_at_idx = 0;
838 
839     uint32_t tries = 0;
840     uint32_t test_idx = 0;
841 
842     while (tries < num_children) {
843       key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
844       val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
845       ;
846       ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
847       if (!process_sp)
848         return lldb::ValueObjectSP();
849       Status error;
850       key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
851       if (error.Fail())
852         return lldb::ValueObjectSP();
853       val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
854       if (error.Fail())
855         return lldb::ValueObjectSP();
856 
857       test_idx++;
858 
859       if (!key_at_idx || !val_at_idx)
860         continue;
861       tries++;
862 
863       DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
864                                              lldb::ValueObjectSP()};
865 
866       m_children.push_back(descriptor);
867     }
868   }
869 
870   if (idx >= m_children.size()) // should never happen
871     return lldb::ValueObjectSP();
872 
873   DictionaryItemDescriptor &dict_item = m_children[idx];
874   if (!dict_item.valobj_sp) {
875     if (!m_pair_type.IsValid()) {
876       TargetSP target_sp(m_backend.GetTargetSP());
877       if (!target_sp)
878         return ValueObjectSP();
879       m_pair_type = GetLLDBNSPairType(target_sp);
880     }
881     if (!m_pair_type.IsValid())
882       return ValueObjectSP();
883 
884     DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
885 
886     if (m_ptr_size == 8) {
887       uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
888       *data_ptr = dict_item.key_ptr;
889       *(data_ptr + 1) = dict_item.val_ptr;
890     } else {
891       uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
892       *data_ptr = dict_item.key_ptr;
893       *(data_ptr + 1) = dict_item.val_ptr;
894     }
895 
896     StreamString idx_name;
897     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
898     DataExtractor data(buffer_sp, m_order, m_ptr_size);
899     dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
900                                                     m_exe_ctx_ref, m_pair_type);
901   }
902   return dict_item.valobj_sp;
903 }
904 
905 
906 lldb_private::formatters::Foundation1100::
907   NSDictionaryMSyntheticFrontEnd::
908     NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
909     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
910       m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
911       m_pair_type() {}
912 
913 lldb_private::formatters::Foundation1100::
914   NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {
915   delete m_data_32;
916   m_data_32 = nullptr;
917   delete m_data_64;
918   m_data_64 = nullptr;
919 }
920 
921 size_t
922 lldb_private::formatters::Foundation1100::
923   NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(const ConstString &name) {
924   const char *item_name = name.GetCString();
925   uint32_t idx = ExtractIndexFromString(item_name);
926   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
927     return UINT32_MAX;
928   return idx;
929 }
930 
931 size_t
932 lldb_private::formatters::Foundation1100::
933   NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
934   if (!m_data_32 && !m_data_64)
935     return 0;
936   return (m_data_32 ? m_data_32->_used : m_data_64->_used);
937 }
938 
939 bool
940 lldb_private::formatters::Foundation1100::
941   NSDictionaryMSyntheticFrontEnd::Update() {
942   m_children.clear();
943   ValueObjectSP valobj_sp = m_backend.GetSP();
944   m_ptr_size = 0;
945   delete m_data_32;
946   m_data_32 = nullptr;
947   delete m_data_64;
948   m_data_64 = nullptr;
949   if (!valobj_sp)
950     return false;
951   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
952   Status error;
953   error.Clear();
954   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
955   if (!process_sp)
956     return false;
957   m_ptr_size = process_sp->GetAddressByteSize();
958   m_order = process_sp->GetByteOrder();
959   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
960   if (m_ptr_size == 4) {
961     m_data_32 = new DataDescriptor_32();
962     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
963                            error);
964   } else {
965     m_data_64 = new DataDescriptor_64();
966     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
967                            error);
968   }
969   if (error.Fail())
970     return false;
971   return false;
972 }
973 
974 bool
975 lldb_private::formatters::Foundation1100::
976   NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
977   return true;
978 }
979 
980 lldb::ValueObjectSP
981 lldb_private::formatters::Foundation1100::
982   NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
983   lldb::addr_t m_keys_ptr =
984       (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
985   lldb::addr_t m_values_ptr =
986       (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
987 
988   uint32_t num_children = CalculateNumChildren();
989 
990   if (idx >= num_children)
991     return lldb::ValueObjectSP();
992 
993   if (m_children.empty()) {
994     // do the scan phase
995     lldb::addr_t key_at_idx = 0, val_at_idx = 0;
996 
997     uint32_t tries = 0;
998     uint32_t test_idx = 0;
999 
1000     while (tries < num_children) {
1001       key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1002       val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1003       ;
1004       ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1005       if (!process_sp)
1006         return lldb::ValueObjectSP();
1007       Status error;
1008       key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1009       if (error.Fail())
1010         return lldb::ValueObjectSP();
1011       val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1012       if (error.Fail())
1013         return lldb::ValueObjectSP();
1014 
1015       test_idx++;
1016 
1017       if (!key_at_idx || !val_at_idx)
1018         continue;
1019       tries++;
1020 
1021       DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1022                                              lldb::ValueObjectSP()};
1023 
1024       m_children.push_back(descriptor);
1025     }
1026   }
1027 
1028   if (idx >= m_children.size()) // should never happen
1029     return lldb::ValueObjectSP();
1030 
1031   DictionaryItemDescriptor &dict_item = m_children[idx];
1032   if (!dict_item.valobj_sp) {
1033     if (!m_pair_type.IsValid()) {
1034       TargetSP target_sp(m_backend.GetTargetSP());
1035       if (!target_sp)
1036         return ValueObjectSP();
1037       m_pair_type = GetLLDBNSPairType(target_sp);
1038     }
1039     if (!m_pair_type.IsValid())
1040       return ValueObjectSP();
1041 
1042     DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1043 
1044     if (m_ptr_size == 8) {
1045       uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1046       *data_ptr = dict_item.key_ptr;
1047       *(data_ptr + 1) = dict_item.val_ptr;
1048     } else {
1049       uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1050       *data_ptr = dict_item.key_ptr;
1051       *(data_ptr + 1) = dict_item.val_ptr;
1052     }
1053 
1054     StreamString idx_name;
1055     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1056     DataExtractor data(buffer_sp, m_order, m_ptr_size);
1057     dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1058                                                     m_exe_ctx_ref, m_pair_type);
1059   }
1060   return dict_item.valobj_sp;
1061 }
1062 
1063 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(
1064     ValueObject &, Stream &, const TypeSummaryOptions &);
1065 
1066 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(
1067     ValueObject &, Stream &, const TypeSummaryOptions &);
1068