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