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