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