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 NSArrayMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
52 public:
53   NSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
54 
55   ~NSArrayMSyntheticFrontEnd() 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 class NSArrayMSyntheticFrontEnd_109 : public NSArrayMSyntheticFrontEnd {
82 public:
83   NSArrayMSyntheticFrontEnd_109(lldb::ValueObjectSP valobj_sp);
84 
85   ~NSArrayMSyntheticFrontEnd_109() override;
86 
87   bool Update() override;
88 
89 protected:
90   lldb::addr_t GetDataAddress() override;
91 
92   uint64_t GetUsedCount() override;
93 
94   uint64_t GetOffset() override;
95 
96   uint64_t GetSize() override;
97 
98 private:
99   struct DataDescriptor_32 {
100     uint32_t _used;
101     uint32_t _priv1 : 2;
102     uint32_t _size : 30;
103     uint32_t _priv2 : 2;
104     uint32_t _offset : 30;
105     uint32_t _priv3;
106     uint32_t _data;
107   };
108 
109   struct DataDescriptor_64 {
110     uint64_t _used;
111     uint64_t _priv1 : 2;
112     uint64_t _size : 62;
113     uint64_t _priv2 : 2;
114     uint64_t _offset : 62;
115     uint32_t _priv3;
116     uint64_t _data;
117   };
118 
119   DataDescriptor_32 *m_data_32;
120   DataDescriptor_64 *m_data_64;
121 };
122 
123 class NSArrayMSyntheticFrontEnd_1010 : public NSArrayMSyntheticFrontEnd {
124 public:
125   NSArrayMSyntheticFrontEnd_1010(lldb::ValueObjectSP valobj_sp);
126 
127   ~NSArrayMSyntheticFrontEnd_1010() override;
128 
129   bool Update() override;
130 
131 protected:
132   lldb::addr_t GetDataAddress() override;
133 
134   uint64_t GetUsedCount() override;
135 
136   uint64_t GetOffset() override;
137 
138   uint64_t GetSize() override;
139 
140 private:
141   struct DataDescriptor_32 {
142     uint32_t _used;
143     uint32_t _offset;
144     uint32_t _size : 28;
145     uint64_t _priv1 : 4;
146     uint32_t _priv2;
147     uint32_t _data;
148   };
149 
150   struct DataDescriptor_64 {
151     uint64_t _used;
152     uint64_t _offset;
153     uint64_t _size : 60;
154     uint64_t _priv1 : 4;
155     uint32_t _priv2;
156     uint64_t _data;
157   };
158 
159   DataDescriptor_32 *m_data_32;
160   DataDescriptor_64 *m_data_64;
161 };
162 
163 class NSArrayMSyntheticFrontEnd_1400 : public NSArrayMSyntheticFrontEnd {
164 public:
165   NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp);
166 
167   ~NSArrayMSyntheticFrontEnd_1400() override;
168 
169   bool Update() override;
170 
171 protected:
172   lldb::addr_t GetDataAddress() override;
173 
174   uint64_t GetUsedCount() override;
175 
176   uint64_t GetOffset() override;
177 
178   uint64_t GetSize() override;
179 
180 private:
181   struct DataDescriptor_32 {
182     uint32_t used;
183     uint32_t offset;
184     uint32_t size;
185     uint32_t list;
186   };
187 
188   struct DataDescriptor_64 {
189     uint64_t used;
190     uint64_t offset;
191     uint64_t size;
192     uint64_t list;
193   };
194 
195   DataDescriptor_32 *m_data_32;
196   DataDescriptor_64 *m_data_64;
197 };
198 
199 class NSArrayISyntheticFrontEnd_1300 : public SyntheticChildrenFrontEnd {
200 public:
201   NSArrayISyntheticFrontEnd_1300(lldb::ValueObjectSP valobj_sp);
202 
203   ~NSArrayISyntheticFrontEnd_1300() override = default;
204 
205   size_t CalculateNumChildren() override;
206 
207   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
208 
209   bool Update() override;
210 
211   bool MightHaveChildren() override;
212 
213   size_t GetIndexOfChildWithName(const ConstString &name) override;
214 
215 private:
216   ExecutionContextRef m_exe_ctx_ref;
217   uint8_t m_ptr_size;
218   uint64_t m_items;
219   lldb::addr_t m_data_ptr;
220   CompilerType m_id_type;
221 };
222 
223 class NSArrayISyntheticFrontEnd_1400 : public SyntheticChildrenFrontEnd {
224 public:
225   NSArrayISyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp);
226 
227   ~NSArrayISyntheticFrontEnd_1400() override;
228 
229   size_t CalculateNumChildren() override;
230 
231   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
232 
233   bool Update() override;
234 
235   bool MightHaveChildren() override;
236 
237   size_t GetIndexOfChildWithName(const ConstString &name) override;
238 
239 private:
240   ExecutionContextRef m_exe_ctx_ref;
241   uint8_t m_ptr_size;
242 
243   struct DataDescriptor_32 {
244     uint32_t used;
245     uint32_t offset;
246     uint32_t size;
247     uint32_t list;
248   };
249 
250   struct DataDescriptor_64 {
251     uint64_t used;
252     uint64_t offset;
253     uint64_t size;
254     uint64_t list;
255   };
256 
257   DataDescriptor_32 *m_data_32;
258   DataDescriptor_64 *m_data_64;
259   CompilerType m_id_type;
260 };
261 
262 class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
263 public:
264   NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
265 
266   ~NSArray0SyntheticFrontEnd() override = default;
267 
268   size_t CalculateNumChildren() override;
269 
270   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
271 
272   bool Update() override;
273 
274   bool MightHaveChildren() override;
275 
276   size_t GetIndexOfChildWithName(const ConstString &name) override;
277 };
278 
279 class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
280 public:
281   NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
282 
283   ~NSArray1SyntheticFrontEnd() override = default;
284 
285   size_t CalculateNumChildren() override;
286 
287   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
288 
289   bool Update() override;
290 
291   bool MightHaveChildren() override;
292 
293   size_t GetIndexOfChildWithName(const ConstString &name) override;
294 };
295 } // namespace formatters
296 } // namespace lldb_private
297 
298 bool lldb_private::formatters::NSArraySummaryProvider(
299     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
300   static ConstString g_TypeHint("NSArray");
301 
302   ProcessSP process_sp = valobj.GetProcessSP();
303   if (!process_sp)
304     return false;
305 
306   ObjCLanguageRuntime *runtime =
307       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
308           lldb::eLanguageTypeObjC);
309 
310   if (!runtime)
311     return false;
312 
313   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
314       runtime->GetClassDescriptor(valobj));
315 
316   if (!descriptor || !descriptor->IsValid())
317     return false;
318 
319   uint32_t ptr_size = process_sp->GetAddressByteSize();
320 
321   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
322 
323   if (!valobj_addr)
324     return false;
325 
326   uint64_t value = 0;
327 
328   ConstString class_name(descriptor->GetClassName());
329 
330   static const ConstString g_NSArrayI("__NSArrayI");
331   static const ConstString g_NSArrayM("__NSArrayM");
332   static const ConstString g_NSArray0("__NSArray0");
333   static const ConstString g_NSArray1("__NSSingleObjectArrayI");
334   static const ConstString g_NSArrayCF("__NSCFArray");
335   static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
336   static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
337 
338   if (class_name.IsEmpty())
339     return false;
340 
341   if (class_name == g_NSArrayI) {
342     Status error;
343     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
344                                                       ptr_size, 0, error);
345     if (error.Fail())
346       return false;
347   } else if (class_name == g_NSArrayM) {
348     Status error;
349     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
350                                                       ptr_size, 0, error);
351     if (error.Fail())
352       return false;
353   } else if (class_name == g_NSArrayMLegacy) {
354     Status error;
355     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
356                                                       ptr_size, 0, error);
357     if (error.Fail())
358       return false;
359   } else if (class_name == g_NSArrayMImmutable) {
360     Status error;
361     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
362                                                       ptr_size, 0, error);
363     if (error.Fail())
364       return false;
365   } else if (class_name == g_NSArray0) {
366     value = 0;
367   } else if (class_name == g_NSArray1) {
368     value = 1;
369   } else if (class_name == g_NSArrayCF) {
370     Status error;
371     value = process_sp->ReadUnsignedIntegerFromMemory(
372         valobj_addr + 2 * ptr_size, ptr_size, 0, error);
373     if (error.Fail())
374       return false;
375   } else {
376     auto &map(NSArray_Additionals::GetAdditionalSummaries());
377     auto iter = map.find(class_name), end = map.end();
378     if (iter != end)
379       return iter->second(valobj, stream, options);
380     else
381       return false;
382   }
383 
384   std::string prefix, suffix;
385   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
386     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
387                                             suffix)) {
388       prefix.clear();
389       suffix.clear();
390     }
391   }
392 
393   stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
394                 value == 1 ? "" : "s", suffix.c_str());
395   return true;
396 }
397 
398 lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd(
399     lldb::ValueObjectSP valobj_sp)
400     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
401       m_id_type() {
402   if (valobj_sp) {
403     clang::ASTContext *ast = valobj_sp->GetExecutionContextRef()
404                                  .GetTargetSP()
405                                  ->GetScratchClangASTContext()
406                                  ->getASTContext();
407     if (ast)
408       m_id_type = CompilerType(ast, ast->ObjCBuiltinIdTy);
409     if (valobj_sp->GetProcessSP())
410       m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
411   }
412 }
413 
414 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::
415     NSArrayMSyntheticFrontEnd_109(lldb::ValueObjectSP valobj_sp)
416     : NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr),
417       m_data_64(nullptr) {}
418 
419 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::
420     NSArrayMSyntheticFrontEnd_1010(lldb::ValueObjectSP valobj_sp)
421     : NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr),
422       m_data_64(nullptr) {}
423 
424 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::
425     NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp)
426     : NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr),
427       m_data_64(nullptr) {}
428 
429 size_t
430 lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren() {
431   return GetUsedCount();
432 }
433 
434 lldb::ValueObjectSP
435 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex(
436     size_t idx) {
437   if (idx >= CalculateNumChildren())
438     return lldb::ValueObjectSP();
439   lldb::addr_t object_at_idx = GetDataAddress();
440   size_t pyhs_idx = idx;
441   pyhs_idx += GetOffset();
442   if (GetSize() <= pyhs_idx)
443     pyhs_idx -= GetSize();
444   object_at_idx += (pyhs_idx * m_ptr_size);
445   StreamString idx_name;
446   idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
447   return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
448                                       m_exe_ctx_ref, m_id_type);
449 }
450 
451 bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::Update() {
452   ValueObjectSP valobj_sp = m_backend.GetSP();
453   m_ptr_size = 0;
454   delete m_data_32;
455   m_data_32 = nullptr;
456   delete m_data_64;
457   m_data_64 = nullptr;
458   if (!valobj_sp)
459     return false;
460   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
461   Status error;
462   error.Clear();
463   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
464   if (!process_sp)
465     return false;
466   m_ptr_size = process_sp->GetAddressByteSize();
467   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
468   if (m_ptr_size == 4) {
469     m_data_32 = new DataDescriptor_32();
470     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
471                            error);
472   } else {
473     m_data_64 = new DataDescriptor_64();
474     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
475                            error);
476   }
477   if (error.Fail())
478     return false;
479   return false;
480 }
481 
482 bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::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 DataDescriptor_32();
501     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
502                            error);
503   } else {
504     m_data_64 = new DataDescriptor_64();
505     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
506                            error);
507   }
508   if (error.Fail())
509     return false;
510   return false;
511 }
512 
513 bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::Update() {
514   ValueObjectSP valobj_sp = m_backend.GetSP();
515   m_ptr_size = 0;
516   delete m_data_32;
517   m_data_32 = nullptr;
518   delete m_data_64;
519   m_data_64 = nullptr;
520   if (!valobj_sp)
521     return false;
522   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
523   Status error;
524   error.Clear();
525   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
526   if (!process_sp)
527     return false;
528   m_ptr_size = process_sp->GetAddressByteSize();
529   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
530   if (m_ptr_size == 4) {
531     m_data_32 = new DataDescriptor_32();
532     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
533                            error);
534   } else {
535     m_data_64 = new DataDescriptor_64();
536     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
537                            error);
538   }
539   if (error.Fail())
540     return false;
541   return false;
542 }
543 
544 bool lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren() {
545   return true;
546 }
547 
548 size_t
549 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName(
550     const ConstString &name) {
551   const char *item_name = name.GetCString();
552   uint32_t idx = ExtractIndexFromString(item_name);
553   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
554     return UINT32_MAX;
555   return idx;
556 }
557 
558 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::
559     ~NSArrayMSyntheticFrontEnd_109() {
560   delete m_data_32;
561   m_data_32 = nullptr;
562   delete m_data_64;
563   m_data_64 = nullptr;
564 }
565 
566 lldb::addr_t
567 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetDataAddress() {
568   if (!m_data_32 && !m_data_64)
569     return LLDB_INVALID_ADDRESS;
570   return m_data_32 ? m_data_32->_data : m_data_64->_data;
571 }
572 
573 uint64_t
574 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetUsedCount() {
575   if (!m_data_32 && !m_data_64)
576     return 0;
577   return m_data_32 ? m_data_32->_used : m_data_64->_used;
578 }
579 
580 uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetOffset() {
581   if (!m_data_32 && !m_data_64)
582     return 0;
583   return m_data_32 ? m_data_32->_offset : m_data_64->_offset;
584 }
585 
586 uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetSize() {
587   if (!m_data_32 && !m_data_64)
588     return 0;
589   return m_data_32 ? m_data_32->_size : m_data_64->_size;
590 }
591 
592 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::
593     ~NSArrayMSyntheticFrontEnd_1010() {
594   delete m_data_32;
595   m_data_32 = nullptr;
596   delete m_data_64;
597   m_data_64 = nullptr;
598 }
599 
600 lldb::addr_t
601 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetDataAddress() {
602   if (!m_data_32 && !m_data_64)
603     return LLDB_INVALID_ADDRESS;
604   return m_data_32 ? m_data_32->_data : m_data_64->_data;
605 }
606 
607 uint64_t
608 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetUsedCount() {
609   if (!m_data_32 && !m_data_64)
610     return 0;
611   return m_data_32 ? m_data_32->_used : m_data_64->_used;
612 }
613 
614 uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetOffset() {
615   if (!m_data_32 && !m_data_64)
616     return 0;
617   return m_data_32 ? m_data_32->_offset : m_data_64->_offset;
618 }
619 
620 uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize() {
621   if (!m_data_32 && !m_data_64)
622     return 0;
623   return m_data_32 ? m_data_32->_size : m_data_64->_size;
624 }
625 
626 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::
627     ~NSArrayMSyntheticFrontEnd_1400() {
628   delete m_data_32;
629   m_data_32 = nullptr;
630   delete m_data_64;
631   m_data_64 = nullptr;
632 }
633 
634 lldb::addr_t
635 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetDataAddress() {
636   if (!m_data_32 && !m_data_64)
637     return LLDB_INVALID_ADDRESS;
638   return m_data_32 ? m_data_32->list : m_data_64->list;
639 }
640 
641 uint64_t
642 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetUsedCount() {
643   if (!m_data_32 && !m_data_64)
644     return 0;
645   return m_data_32 ? m_data_32->used : m_data_64->used;
646 }
647 
648 uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetOffset() {
649   if (!m_data_32 && !m_data_64)
650     return 0;
651   return m_data_32 ? m_data_32->offset : m_data_64->offset;
652 }
653 
654 uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetSize() {
655   if (!m_data_32 && !m_data_64)
656     return 0;
657   return m_data_32 ? m_data_32->size : m_data_64->size;
658 }
659 
660 
661 lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::NSArrayISyntheticFrontEnd_1300(
662     lldb::ValueObjectSP valobj_sp)
663     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
664       m_items(0), m_data_ptr(0) {
665   if (valobj_sp) {
666     CompilerType type = valobj_sp->GetCompilerType();
667     if (type) {
668       ClangASTContext *ast = valobj_sp->GetExecutionContextRef()
669                                  .GetTargetSP()
670                                  ->GetScratchClangASTContext();
671       if (ast)
672         m_id_type = CompilerType(ast->getASTContext(),
673                                  ast->getASTContext()->ObjCBuiltinIdTy);
674     }
675   }
676 }
677 
678 size_t
679 lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetIndexOfChildWithName(
680     const ConstString &name) {
681   const char *item_name = name.GetCString();
682   uint32_t idx = ExtractIndexFromString(item_name);
683   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
684     return UINT32_MAX;
685   return idx;
686 }
687 
688 size_t
689 lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::CalculateNumChildren() {
690   return m_items;
691 }
692 
693 bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::Update() {
694   m_ptr_size = 0;
695   m_items = 0;
696   m_data_ptr = 0;
697   ValueObjectSP valobj_sp = m_backend.GetSP();
698   if (!valobj_sp)
699     return false;
700   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
701   Status error;
702   error.Clear();
703   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
704   if (!process_sp)
705     return false;
706   m_ptr_size = process_sp->GetAddressByteSize();
707   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
708   m_items = process_sp->ReadPointerFromMemory(data_location, error);
709   if (error.Fail())
710     return false;
711   m_data_ptr = data_location + m_ptr_size;
712   return false;
713 }
714 
715 bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::MightHaveChildren() {
716   return true;
717 }
718 
719 lldb::ValueObjectSP
720 lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetChildAtIndex(
721     size_t idx) {
722   if (idx >= CalculateNumChildren())
723     return lldb::ValueObjectSP();
724   lldb::addr_t object_at_idx = m_data_ptr;
725   object_at_idx += (idx * m_ptr_size);
726   ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
727   if (!process_sp)
728     return lldb::ValueObjectSP();
729   Status error;
730   if (error.Fail())
731     return lldb::ValueObjectSP();
732   StreamString idx_name;
733   idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
734   return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
735                                       m_exe_ctx_ref, m_id_type);
736 }
737 
738 lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::NSArrayISyntheticFrontEnd_1400(
739     lldb::ValueObjectSP valobj_sp)
740     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
741       m_data_32(nullptr), m_data_64(nullptr) {
742   if (valobj_sp) {
743     CompilerType type = valobj_sp->GetCompilerType();
744     if (type) {
745       ClangASTContext *ast = valobj_sp->GetExecutionContextRef()
746                                  .GetTargetSP()
747                                  ->GetScratchClangASTContext();
748       if (ast)
749         m_id_type = CompilerType(ast->getASTContext(),
750                                  ast->getASTContext()->ObjCBuiltinIdTy);
751     }
752   }
753 }
754 
755 lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::~NSArrayISyntheticFrontEnd_1400() {
756   delete m_data_32;
757   m_data_32 = nullptr;
758   delete m_data_64;
759   m_data_64 = nullptr;
760 }
761 
762 size_t
763 lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetIndexOfChildWithName(
764     const ConstString &name) {
765   const char *item_name = name.GetCString();
766   uint32_t idx = ExtractIndexFromString(item_name);
767   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
768     return UINT32_MAX;
769   return idx;
770 }
771 
772 size_t
773 lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::CalculateNumChildren() {
774   return m_data_32 ? m_data_32->used : m_data_64->used;
775 }
776 
777 bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::Update() {
778   ValueObjectSP valobj_sp = m_backend.GetSP();
779   m_ptr_size = 0;
780   delete m_data_32;
781   m_data_32 = nullptr;
782   delete m_data_64;
783   m_data_64 = nullptr;
784   if (!valobj_sp)
785     return false;
786   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
787   Status error;
788   error.Clear();
789   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
790   if (!process_sp)
791     return false;
792   m_ptr_size = process_sp->GetAddressByteSize();
793   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
794   if (m_ptr_size == 4) {
795     m_data_32 = new DataDescriptor_32();
796     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
797                            error);
798   } else {
799     m_data_64 = new DataDescriptor_64();
800     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
801                            error);
802   }
803   if (error.Fail())
804     return false;
805   return false;
806 }
807 
808 bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::MightHaveChildren() {
809   return true;
810 }
811 
812 lldb::ValueObjectSP
813 lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetChildAtIndex(
814     size_t idx) {
815   if (idx >= CalculateNumChildren())
816     return lldb::ValueObjectSP();
817   lldb::addr_t object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
818   object_at_idx += (idx * m_ptr_size);
819   ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
820   if (!process_sp)
821     return lldb::ValueObjectSP();
822   Status error;
823   if (error.Fail())
824     return lldb::ValueObjectSP();
825   StreamString idx_name;
826   idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
827   return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
828                                       m_exe_ctx_ref, m_id_type);
829 }
830 
831 lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
832     lldb::ValueObjectSP valobj_sp)
833     : SyntheticChildrenFrontEnd(*valobj_sp) {}
834 
835 size_t
836 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(
837     const ConstString &name) {
838   return UINT32_MAX;
839 }
840 
841 size_t
842 lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {
843   return 0;
844 }
845 
846 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {
847   return false;
848 }
849 
850 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {
851   return false;
852 }
853 
854 lldb::ValueObjectSP
855 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(
856     size_t idx) {
857   return lldb::ValueObjectSP();
858 }
859 
860 lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(
861     lldb::ValueObjectSP valobj_sp)
862     : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}
863 
864 size_t
865 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(
866     const ConstString &name) {
867   static const ConstString g_zero("[0]");
868 
869   if (name == g_zero)
870     return 0;
871 
872   return UINT32_MAX;
873 }
874 
875 size_t
876 lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {
877   return 1;
878 }
879 
880 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {
881   return false;
882 }
883 
884 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() {
885   return true;
886 }
887 
888 lldb::ValueObjectSP
889 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(
890     size_t idx) {
891   static const ConstString g_zero("[0]");
892 
893   if (idx == 0) {
894     CompilerType id_type(
895         m_backend.GetTargetSP()->GetScratchClangASTContext()->GetBasicType(
896             lldb::eBasicTypeObjCID));
897     return m_backend.GetSyntheticChildAtOffset(
898         m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true, g_zero);
899   }
900   return lldb::ValueObjectSP();
901 }
902 
903 SyntheticChildrenFrontEnd *
904 lldb_private::formatters::NSArraySyntheticFrontEndCreator(
905     CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
906   if (!valobj_sp)
907     return nullptr;
908 
909   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
910   if (!process_sp)
911     return nullptr;
912   AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
913       process_sp->GetObjCLanguageRuntime());
914   if (!runtime)
915     return nullptr;
916 
917   CompilerType valobj_type(valobj_sp->GetCompilerType());
918   Flags flags(valobj_type.GetTypeInfo());
919 
920   if (flags.IsClear(eTypeIsPointer)) {
921     Status error;
922     valobj_sp = valobj_sp->AddressOf(error);
923     if (error.Fail() || !valobj_sp)
924       return nullptr;
925   }
926 
927   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
928       runtime->GetClassDescriptor(*valobj_sp));
929 
930   if (!descriptor || !descriptor->IsValid())
931     return nullptr;
932 
933   ConstString class_name(descriptor->GetClassName());
934 
935   static const ConstString g_NSArrayI("__NSArrayI");
936   static const ConstString g_NSArrayM("__NSArrayM");
937   static const ConstString g_NSArray0("__NSArray0");
938   static const ConstString g_NSArray1("__NSSingleObjectArrayI");
939   static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
940   static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
941 
942   if (class_name.IsEmpty())
943     return nullptr;
944 
945   if (class_name == g_NSArrayI) {
946       if (runtime->GetFoundationVersion() >= 1400)
947         return (new NSArrayISyntheticFrontEnd_1400(valobj_sp));
948       else
949         return (new NSArrayISyntheticFrontEnd_1300(valobj_sp));
950   } else if (class_name == g_NSArray0) {
951     return (new NSArray0SyntheticFrontEnd(valobj_sp));
952   } else if (class_name == g_NSArray1) {
953     return (new NSArray1SyntheticFrontEnd(valobj_sp));
954   } else if (class_name == g_NSArrayM) {
955     if (runtime->GetFoundationVersion() >= 1400)
956       return (new NSArrayMSyntheticFrontEnd_1400(valobj_sp));
957     if (runtime->GetFoundationVersion() >= 1100)
958       return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp));
959     else
960       return (new NSArrayMSyntheticFrontEnd_109(valobj_sp));
961   } else {
962     auto &map(NSArray_Additionals::GetAdditionalSynthetics());
963     auto iter = map.find(class_name), end = map.end();
964     if (iter != end)
965       return iter->second(synth, valobj_sp);
966   }
967 
968   return nullptr;
969 }
970