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