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