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