]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp
Upgrade to OpenSSH 7.7p1.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / Language / ObjC / NSArray.cpp
1 //===-- NSArray.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 // Other libraries and framework includes
13 #include "clang/AST/ASTContext.h"
14
15 // Project includes
16 #include "Cocoa.h"
17
18 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
19 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Core/ValueObjectConstResult.h"
21 #include "lldb/DataFormatters/FormattersHelpers.h"
22 #include "lldb/Expression/FunctionCaller.h"
23 #include "lldb/Symbol/ClangASTContext.h"
24 #include "lldb/Target/Language.h"
25 #include "lldb/Target/ObjCLanguageRuntime.h"
26 #include "lldb/Target/Target.h"
27 #include "lldb/Utility/DataBufferHeap.h"
28 #include "lldb/Utility/Endian.h"
29 #include "lldb/Utility/Status.h"
30 #include "lldb/Utility/Stream.h"
31
32 using namespace lldb;
33 using namespace lldb_private;
34 using namespace lldb_private::formatters;
35
36 namespace lldb_private {
37 namespace formatters {
38 std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
39 NSArray_Additionals::GetAdditionalSummaries() {
40   static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
41   return g_map;
42 }
43
44 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
45 NSArray_Additionals::GetAdditionalSynthetics() {
46   static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
47       g_map;
48   return g_map;
49 }
50
51 class NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd {
52 public:
53   NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp);
54
55   ~NSArrayMSyntheticFrontEndBase() override = default;
56
57   size_t CalculateNumChildren() override;
58
59   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
60
61   bool Update() override = 0;
62
63   bool MightHaveChildren() override;
64
65   size_t GetIndexOfChildWithName(const ConstString &name) override;
66
67 protected:
68   virtual lldb::addr_t GetDataAddress() = 0;
69
70   virtual uint64_t GetUsedCount() = 0;
71
72   virtual uint64_t GetOffset() = 0;
73
74   virtual uint64_t GetSize() = 0;
75
76   ExecutionContextRef m_exe_ctx_ref;
77   uint8_t m_ptr_size;
78   CompilerType m_id_type;
79 };
80
81 template <typename D32, typename D64>
82 class GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase {
83 public:
84   GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
85
86   ~GenericNSArrayMSyntheticFrontEnd() override;
87
88   bool Update() override;
89
90 protected:
91   lldb::addr_t GetDataAddress() override;
92
93   uint64_t GetUsedCount() override;
94
95   uint64_t GetOffset() override;
96
97   uint64_t GetSize() override;
98
99 private:
100   D32 *m_data_32;
101   D64 *m_data_64;
102 };
103   
104 namespace Foundation109 {
105   struct DataDescriptor_32 {
106     uint32_t _used;
107     uint32_t _priv1 : 2;
108     uint32_t _size : 30;
109     uint32_t _priv2 : 2;
110     uint32_t _offset : 30;
111     uint32_t _priv3;
112     uint32_t _data;
113   };
114   
115   struct DataDescriptor_64 {
116     uint64_t _used;
117     uint64_t _priv1 : 2;
118     uint64_t _size : 62;
119     uint64_t _priv2 : 2;
120     uint64_t _offset : 62;
121     uint32_t _priv3;
122     uint64_t _data;
123   };
124   
125   using NSArrayMSyntheticFrontEnd =
126       GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
127 }
128   
129 namespace Foundation1010 {
130   struct DataDescriptor_32 {
131     uint32_t _used;
132     uint32_t _offset;
133     uint32_t _size : 28;
134     uint64_t _priv1 : 4;
135     uint32_t _priv2;
136     uint32_t _data;
137   };
138   
139   struct DataDescriptor_64 {
140     uint64_t _used;
141     uint64_t _offset;
142     uint64_t _size : 60;
143     uint64_t _priv1 : 4;
144     uint32_t _priv2;
145     uint64_t _data;
146   };
147   
148   using NSArrayMSyntheticFrontEnd =
149       GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
150 }
151   
152 namespace Foundation1428 {
153   struct DataDescriptor_32 {
154     uint32_t _used;
155     uint32_t _offset;
156     uint32_t _size;
157     uint32_t _data;
158   };
159   
160   struct DataDescriptor_64 {
161     uint64_t _used;
162     uint64_t _offset;
163     uint64_t _size;
164     uint64_t _data;
165   };
166   
167   using NSArrayMSyntheticFrontEnd =
168       GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
169 }
170   
171 namespace Foundation1437 {
172   template <typename PtrType>
173   struct DataDescriptor {
174     PtrType _cow;
175     // __deque
176     PtrType _data;
177     uint32_t _offset;
178     uint32_t _size;
179     union {
180       PtrType _mutations;
181       struct {
182         uint32_t _muts;
183         uint32_t _used;
184       };
185     };
186   };
187     
188   using NSArrayMSyntheticFrontEnd =
189      GenericNSArrayMSyntheticFrontEnd<
190         DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>;
191   
192   template <typename DD>
193   uint64_t
194   __NSArrayMSize_Impl(lldb_private::Process &process,
195                       lldb::addr_t valobj_addr, Status &error) {
196     const lldb::addr_t start_of_descriptor =
197     valobj_addr + process.GetAddressByteSize();
198     DD descriptor = DD();
199     process.ReadMemory(start_of_descriptor, &descriptor,
200                        sizeof(descriptor), error);
201     if (error.Fail()) {
202       return 0;
203     }
204     return descriptor._used;
205   }
206   
207   uint64_t
208   __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
209                  Status &error) {
210     if (process.GetAddressByteSize() == 4) {
211       return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr,
212                                                            error);
213     } else {
214       return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr,
215                                                            error);
216     }
217   }
218
219 }
220
221 template <typename D32, typename D64, bool Inline>
222 class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
223 public:
224   GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
225
226   ~GenericNSArrayISyntheticFrontEnd() override;
227
228   size_t CalculateNumChildren() override;
229
230   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
231
232   bool Update() override;
233
234   bool MightHaveChildren() override;
235
236   size_t GetIndexOfChildWithName(const ConstString &name) override;
237
238 private:
239   ExecutionContextRef m_exe_ctx_ref;
240   uint8_t m_ptr_size;
241     
242   D32 *m_data_32;
243   D64 *m_data_64;
244   CompilerType m_id_type;
245 };
246     
247 namespace Foundation1300 {
248     struct IDD32 {
249         uint32_t used;
250         uint32_t list;
251     };
252     
253     struct IDD64 {
254         uint64_t used;
255         uint64_t list;
256     };
257     
258     using NSArrayISyntheticFrontEnd =
259         GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
260 }
261
262 namespace Foundation1430 {
263     using NSArrayISyntheticFrontEnd =
264         Foundation1428::NSArrayMSyntheticFrontEnd;
265 }
266
267 namespace Foundation1436 {
268     struct IDD32 {
269         uint32_t used;
270         uint32_t list; // in Inline cases, this is the first element
271     };
272     
273     struct IDD64 {
274         uint64_t used;
275         uint64_t list; // in Inline cases, this is the first element
276     };
277     
278     using NSArrayI_TransferSyntheticFrontEnd =
279         GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>;
280
281     using NSArrayISyntheticFrontEnd =
282         GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
283     
284     using NSFrozenArrayMSyntheticFrontEnd =
285         Foundation1437::NSArrayMSyntheticFrontEnd;
286
287     uint64_t
288     __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
289                          Status &error) {
290       return Foundation1437::__NSArrayMSize(process, valobj_addr, error);
291     }
292 }
293
294 class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
295 public:
296   NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
297
298   ~NSArray0SyntheticFrontEnd() override = default;
299
300   size_t CalculateNumChildren() override;
301
302   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
303
304   bool Update() override;
305
306   bool MightHaveChildren() override;
307
308   size_t GetIndexOfChildWithName(const ConstString &name) override;
309 };
310
311 class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
312 public:
313   NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
314
315   ~NSArray1SyntheticFrontEnd() override = default;
316
317   size_t CalculateNumChildren() override;
318
319   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
320
321   bool Update() override;
322
323   bool MightHaveChildren() override;
324
325   size_t GetIndexOfChildWithName(const ConstString &name) override;
326 };
327 } // namespace formatters
328 } // namespace lldb_private
329
330 bool lldb_private::formatters::NSArraySummaryProvider(
331     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
332   static ConstString g_TypeHint("NSArray");
333
334   ProcessSP process_sp = valobj.GetProcessSP();
335   if (!process_sp)
336     return false;
337
338   ObjCLanguageRuntime *runtime =
339       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
340           lldb::eLanguageTypeObjC);
341
342   if (!runtime)
343     return false;
344
345   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
346       runtime->GetClassDescriptor(valobj));
347
348   if (!descriptor || !descriptor->IsValid())
349     return false;
350
351   uint32_t ptr_size = process_sp->GetAddressByteSize();
352
353   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
354
355   if (!valobj_addr)
356     return false;
357
358   uint64_t value = 0;
359
360   ConstString class_name(descriptor->GetClassName());
361
362   static const ConstString g_NSArrayI("__NSArrayI");
363   static const ConstString g_NSArrayM("__NSArrayM");
364   static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
365   static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
366   static const ConstString g_NSArray0("__NSArray0");
367   static const ConstString g_NSArray1("__NSSingleObjectArrayI");
368   static const ConstString g_NSArrayCF("__NSCFArray");
369   static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
370   static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
371
372   if (class_name.IsEmpty())
373     return false;
374
375   if (class_name == g_NSArrayI) {
376     Status error;
377     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
378                                                       ptr_size, 0, error);
379     if (error.Fail())
380       return false;
381   } else if (class_name == g_NSArrayM) {
382     AppleObjCRuntime *apple_runtime =
383     llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
384     Status error;
385     if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
386       value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error);
387     } else {
388       value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
389                                                         ptr_size, 0, error);
390     }
391     if (error.Fail())
392       return false;
393   } else if (class_name == g_NSArrayI_Transfer) {
394     Status error;
395     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
396                                                       ptr_size, 0, error);
397     if (error.Fail())
398       return false;
399   } else if (class_name == g_NSFrozenArrayM) {
400     Status error;
401     value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error);
402     if (error.Fail())
403       return false;
404   } else if (class_name == g_NSArrayMLegacy) {
405     Status error;
406     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
407                                                       ptr_size, 0, error);
408     if (error.Fail())
409       return false;
410   } else if (class_name == g_NSArrayMImmutable) {
411     Status error;
412     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
413                                                       ptr_size, 0, error);
414     if (error.Fail())
415       return false;
416   } else if (class_name == g_NSArray0) {
417     value = 0;
418   } else if (class_name == g_NSArray1) {
419     value = 1;
420   } else if (class_name == g_NSArrayCF) {
421     Status error;
422     value = process_sp->ReadUnsignedIntegerFromMemory(
423         valobj_addr + 2 * ptr_size, ptr_size, 0, error);
424     if (error.Fail())
425       return false;
426   } else {
427     auto &map(NSArray_Additionals::GetAdditionalSummaries());
428     auto iter = map.find(class_name), end = map.end();
429     if (iter != end)
430       return iter->second(valobj, stream, options);
431     else
432       return false;
433   }
434
435   std::string prefix, suffix;
436   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
437     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
438                                             suffix)) {
439       prefix.clear();
440       suffix.clear();
441     }
442   }
443
444   stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
445                 value == 1 ? "" : "s", suffix.c_str());
446   return true;
447 }
448
449 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontEndBase(
450     lldb::ValueObjectSP valobj_sp)
451     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
452       m_id_type() {
453   if (valobj_sp) {
454     clang::ASTContext *ast = valobj_sp->GetExecutionContextRef()
455                                  .GetTargetSP()
456                                  ->GetScratchClangASTContext()
457                                  ->getASTContext();
458     if (ast)
459       m_id_type = CompilerType(ast, ast->ObjCBuiltinIdTy);
460     if (valobj_sp->GetProcessSP())
461       m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
462   }
463 }
464
465 template <typename D32, typename D64>
466 lldb_private::formatters::
467   GenericNSArrayMSyntheticFrontEnd<D32, D64>::
468     GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
469     : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr),
470       m_data_64(nullptr) {}
471
472 size_t
473 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::CalculateNumChildren() {
474   return GetUsedCount();
475 }
476
477 lldb::ValueObjectSP
478 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(
479     size_t idx) {
480   if (idx >= CalculateNumChildren())
481     return lldb::ValueObjectSP();
482   lldb::addr_t object_at_idx = GetDataAddress();
483   size_t pyhs_idx = idx;
484   pyhs_idx += GetOffset();
485   if (GetSize() <= pyhs_idx)
486     pyhs_idx -= GetSize();
487   object_at_idx += (pyhs_idx * m_ptr_size);
488   StreamString idx_name;
489   idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
490   return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
491                                       m_exe_ctx_ref, m_id_type);
492 }
493
494 template <typename D32, typename D64>
495 bool
496 lldb_private::formatters::
497   GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {
498   ValueObjectSP valobj_sp = m_backend.GetSP();
499   m_ptr_size = 0;
500   delete m_data_32;
501   m_data_32 = nullptr;
502   delete m_data_64;
503   m_data_64 = nullptr;
504   if (!valobj_sp)
505     return false;
506   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
507   Status error;
508   error.Clear();
509   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
510   if (!process_sp)
511     return false;
512   m_ptr_size = process_sp->GetAddressByteSize();
513   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
514   if (m_ptr_size == 4) {
515     m_data_32 = new D32();
516     process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
517                            error);
518   } else {
519     m_data_64 = new D64();
520     process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
521                            error);
522   }
523   if (error.Fail())
524     return false;
525   return false;
526 }
527
528 bool
529 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::MightHaveChildren() {
530   return true;
531 }
532
533 size_t
534 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName(
535     const ConstString &name) {
536   const char *item_name = name.GetCString();
537   uint32_t idx = ExtractIndexFromString(item_name);
538   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
539     return UINT32_MAX;
540   return idx;
541 }
542
543 template <typename D32, typename D64>
544 lldb_private::formatters::
545   GenericNSArrayMSyntheticFrontEnd<D32, D64>::
546     ~GenericNSArrayMSyntheticFrontEnd() {
547   delete m_data_32;
548   m_data_32 = nullptr;
549   delete m_data_64;
550   m_data_64 = nullptr;
551 }
552
553 template <typename D32, typename D64>
554 lldb::addr_t
555 lldb_private::formatters::
556   GenericNSArrayMSyntheticFrontEnd<D32, D64>::
557     GenericNSArrayMSyntheticFrontEnd::GetDataAddress() {
558   if (!m_data_32 && !m_data_64)
559     return LLDB_INVALID_ADDRESS;
560   return m_data_32 ? m_data_32->_data : m_data_64->_data;
561 }
562
563 template <typename D32, typename D64>
564 uint64_t
565 lldb_private::formatters::
566   GenericNSArrayMSyntheticFrontEnd<D32, D64>::
567     GenericNSArrayMSyntheticFrontEnd::GetUsedCount() {
568   if (!m_data_32 && !m_data_64)
569     return 0;
570   return m_data_32 ? m_data_32->_used : m_data_64->_used;
571 }
572
573 template <typename D32, typename D64>
574 uint64_t
575 lldb_private::formatters::
576   GenericNSArrayMSyntheticFrontEnd<D32, D64>::
577     GenericNSArrayMSyntheticFrontEnd::GetOffset() {
578   if (!m_data_32 && !m_data_64)
579     return 0;
580   return m_data_32 ? m_data_32->_offset : m_data_64->_offset;
581 }
582
583 template <typename D32, typename D64>
584 uint64_t
585 lldb_private::formatters::
586   GenericNSArrayMSyntheticFrontEnd<D32, D64>::
587     GenericNSArrayMSyntheticFrontEnd::GetSize() {
588   if (!m_data_32 && !m_data_64)
589     return 0;
590   return m_data_32 ? m_data_32->_size : m_data_64->_size;
591 }
592
593 template <typename D32, typename D64, bool Inline>
594 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
595   GenericNSArrayISyntheticFrontEnd(
596     lldb::ValueObjectSP valobj_sp)
597     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
598       m_data_32(nullptr), m_data_64(nullptr) {
599   if (valobj_sp) {
600     CompilerType type = valobj_sp->GetCompilerType();
601     if (type) {
602       ClangASTContext *ast = valobj_sp->GetExecutionContextRef()
603                                  .GetTargetSP()
604                                  ->GetScratchClangASTContext();
605       if (ast)
606         m_id_type = CompilerType(ast->getASTContext(),
607                                  ast->getASTContext()->ObjCBuiltinIdTy);
608     }
609   }
610 }
611
612 template <typename D32, typename D64, bool Inline>
613 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
614   ~GenericNSArrayISyntheticFrontEnd() {
615   delete m_data_32;
616   m_data_32 = nullptr;
617   delete m_data_64;
618   m_data_64 = nullptr;
619 }
620
621 template <typename D32, typename D64, bool Inline>
622 size_t
623 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
624   GetIndexOfChildWithName(const ConstString &name) {
625   const char *item_name = name.GetCString();
626   uint32_t idx = ExtractIndexFromString(item_name);
627   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
628     return UINT32_MAX;
629   return idx;
630 }
631
632 template <typename D32, typename D64, bool Inline>
633 size_t
634 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
635   CalculateNumChildren() {
636   return m_data_32 ? m_data_32->used : m_data_64->used;
637 }
638
639 template <typename D32, typename D64, bool Inline>
640 bool
641 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
642   Update() {
643   ValueObjectSP valobj_sp = m_backend.GetSP();
644   m_ptr_size = 0;
645   delete m_data_32;
646   m_data_32 = nullptr;
647   delete m_data_64;
648   m_data_64 = nullptr;
649   if (!valobj_sp)
650     return false;
651   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
652   Status error;
653   error.Clear();
654   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
655   if (!process_sp)
656     return false;
657   m_ptr_size = process_sp->GetAddressByteSize();
658   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
659   if (m_ptr_size == 4) {
660     m_data_32 = new D32();
661     process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
662                            error);
663   } else {
664     m_data_64 = new D64();
665     process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
666                            error);
667   }
668   if (error.Fail())
669     return false;
670   return false;
671 }
672
673 template <typename D32, typename D64, bool Inline>
674 bool
675 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
676   MightHaveChildren() {
677   return true;
678 }
679
680 template <typename D32, typename D64, bool Inline>
681 lldb::ValueObjectSP
682 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
683   GetChildAtIndex(size_t idx) {
684   if (idx >= CalculateNumChildren())
685     return lldb::ValueObjectSP();
686   lldb::addr_t object_at_idx;
687   if (Inline) {
688     object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size;
689     object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header
690     object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer
691   } else {
692     object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
693   }
694   object_at_idx += (idx * m_ptr_size);
695
696   ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
697   if (!process_sp)
698     return lldb::ValueObjectSP();
699   Status error;
700   if (error.Fail())
701     return lldb::ValueObjectSP();
702   StreamString idx_name;
703   idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
704   return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
705                                       m_exe_ctx_ref, m_id_type);
706 }
707
708 lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
709     lldb::ValueObjectSP valobj_sp)
710     : SyntheticChildrenFrontEnd(*valobj_sp) {}
711
712 size_t
713 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(
714     const ConstString &name) {
715   return UINT32_MAX;
716 }
717
718 size_t
719 lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {
720   return 0;
721 }
722
723 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {
724   return false;
725 }
726
727 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {
728   return false;
729 }
730
731 lldb::ValueObjectSP
732 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(
733     size_t idx) {
734   return lldb::ValueObjectSP();
735 }
736
737 lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(
738     lldb::ValueObjectSP valobj_sp)
739     : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}
740
741 size_t
742 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(
743     const ConstString &name) {
744   static const ConstString g_zero("[0]");
745
746   if (name == g_zero)
747     return 0;
748
749   return UINT32_MAX;
750 }
751
752 size_t
753 lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {
754   return 1;
755 }
756
757 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {
758   return false;
759 }
760
761 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() {
762   return true;
763 }
764
765 lldb::ValueObjectSP
766 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(
767     size_t idx) {
768   static const ConstString g_zero("[0]");
769
770   if (idx == 0) {
771     CompilerType id_type(
772         m_backend.GetTargetSP()->GetScratchClangASTContext()->GetBasicType(
773             lldb::eBasicTypeObjCID));
774     return m_backend.GetSyntheticChildAtOffset(
775         m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true, g_zero);
776   }
777   return lldb::ValueObjectSP();
778 }
779
780 SyntheticChildrenFrontEnd *
781 lldb_private::formatters::NSArraySyntheticFrontEndCreator(
782     CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
783   if (!valobj_sp)
784     return nullptr;
785
786   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
787   if (!process_sp)
788     return nullptr;
789   AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
790       process_sp->GetObjCLanguageRuntime());
791   if (!runtime)
792     return nullptr;
793
794   CompilerType valobj_type(valobj_sp->GetCompilerType());
795   Flags flags(valobj_type.GetTypeInfo());
796
797   if (flags.IsClear(eTypeIsPointer)) {
798     Status error;
799     valobj_sp = valobj_sp->AddressOf(error);
800     if (error.Fail() || !valobj_sp)
801       return nullptr;
802   }
803
804   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
805       runtime->GetClassDescriptor(*valobj_sp));
806
807   if (!descriptor || !descriptor->IsValid())
808     return nullptr;
809
810   ConstString class_name(descriptor->GetClassName());
811
812   static const ConstString g_NSArrayI("__NSArrayI");
813   static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
814   static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
815   static const ConstString g_NSArrayM("__NSArrayM");
816   static const ConstString g_NSArray0("__NSArray0");
817   static const ConstString g_NSArray1("__NSSingleObjectArrayI");
818   static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
819   static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
820
821   if (class_name.IsEmpty())
822     return nullptr;
823
824   if (class_name == g_NSArrayI) {
825     if (runtime->GetFoundationVersion() >= 1436)
826       return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp));
827     if (runtime->GetFoundationVersion() >= 1430)
828       return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp));
829     else
830       return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));
831   } else if (class_name == g_NSArrayI_Transfer) {
832       return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));
833   } else if (class_name == g_NSArray0) {
834   } else if (class_name == g_NSFrozenArrayM) {
835     return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));
836   } else if (class_name == g_NSArray0) {
837     return (new NSArray0SyntheticFrontEnd(valobj_sp));
838   } else if (class_name == g_NSArray1) {
839     return (new NSArray1SyntheticFrontEnd(valobj_sp));
840   } else if (class_name == g_NSArrayM) {
841     if (runtime->GetFoundationVersion() >= 1437)
842       return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp));
843     if (runtime->GetFoundationVersion() >= 1428)
844       return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp));
845     if (runtime->GetFoundationVersion() >= 1100)
846       return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));
847     else
848       return (new Foundation109::NSArrayMSyntheticFrontEnd(valobj_sp));
849   } else {
850     auto &map(NSArray_Additionals::GetAdditionalSynthetics());
851     auto iter = map.find(class_name), end = map.end();
852     if (iter != end)
853       return iter->second(synth, valobj_sp);
854   }
855
856   return nullptr;
857 }