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