1 //===-- NSArray.cpp ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "Cocoa.h"
11 
12 #include "lldb/Core/DataBufferHeap.h"
13 #include "lldb/Core/Error.h"
14 #include "lldb/Core/Stream.h"
15 #include "lldb/Core/ValueObject.h"
16 #include "lldb/Core/ValueObjectConstResult.h"
17 #include "lldb/DataFormatters/FormattersHelpers.h"
18 #include "lldb/Expression/FunctionCaller.h"
19 #include "lldb/Host/Endian.h"
20 #include "lldb/Symbol/ClangASTContext.h"
21 #include "lldb/Target/Language.h"
22 #include "lldb/Target/ObjCLanguageRuntime.h"
23 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
24 #include "lldb/Target/Target.h"
25 
26 #include "clang/AST/ASTContext.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 using namespace lldb_private::formatters;
31 
32 namespace  lldb_private {
33     namespace formatters {
34         class NSArrayMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
35         {
36         public:
37             NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
38 
39             virtual size_t
40             CalculateNumChildren ();
41 
42             virtual lldb::ValueObjectSP
43             GetChildAtIndex (size_t idx);
44 
45             virtual bool
46             Update() = 0;
47 
48             virtual bool
49             MightHaveChildren ();
50 
51             virtual size_t
52             GetIndexOfChildWithName (const ConstString &name);
53 
54             virtual
55             ~NSArrayMSyntheticFrontEnd () {}
56 
57         protected:
58             virtual lldb::addr_t
59             GetDataAddress () = 0;
60 
61             virtual uint64_t
62             GetUsedCount () = 0;
63 
64             virtual uint64_t
65             GetOffset () = 0;
66 
67             virtual uint64_t
68             GetSize () = 0;
69 
70             ExecutionContextRef m_exe_ctx_ref;
71             uint8_t m_ptr_size;
72             CompilerType m_id_type;
73             std::vector<lldb::ValueObjectSP> m_children;
74         };
75 
76         class NSArrayMSyntheticFrontEnd_109 : public NSArrayMSyntheticFrontEnd
77         {
78         private:
79             struct DataDescriptor_32
80             {
81                 uint32_t _used;
82                 uint32_t _priv1 : 2 ;
83                 uint32_t _size : 30;
84                 uint32_t _priv2 : 2;
85                 uint32_t _offset : 30;
86                 uint32_t _priv3;
87                 uint32_t _data;
88             };
89             struct DataDescriptor_64
90             {
91                 uint64_t _used;
92                 uint64_t _priv1 : 2 ;
93                 uint64_t _size : 62;
94                 uint64_t _priv2 : 2;
95                 uint64_t _offset : 62;
96                 uint32_t _priv3;
97                 uint64_t _data;
98             };
99         public:
100             NSArrayMSyntheticFrontEnd_109 (lldb::ValueObjectSP valobj_sp);
101 
102             virtual bool
103             Update();
104 
105             virtual
106             ~NSArrayMSyntheticFrontEnd_109 ();
107 
108         protected:
109             virtual lldb::addr_t
110             GetDataAddress ();
111 
112             virtual uint64_t
113             GetUsedCount ();
114 
115             virtual uint64_t
116             GetOffset ();
117 
118             virtual uint64_t
119             GetSize ();
120 
121         private:
122             DataDescriptor_32 *m_data_32;
123             DataDescriptor_64 *m_data_64;
124         };
125 
126         class NSArrayMSyntheticFrontEnd_1010 : public NSArrayMSyntheticFrontEnd
127         {
128         private:
129             struct DataDescriptor_32
130             {
131                 uint32_t _used;
132                 uint32_t _offset;
133                 uint32_t _size : 28;
134                 uint64_t _priv1 : 4;
135                 uint32_t _priv2;
136                 uint32_t _data;
137             };
138             struct DataDescriptor_64
139             {
140                 uint64_t _used;
141                 uint64_t _offset;
142                 uint64_t _size : 60;
143                 uint64_t _priv1 : 4;
144                 uint32_t _priv2;
145                 uint64_t _data;
146             };
147         public:
148             NSArrayMSyntheticFrontEnd_1010 (lldb::ValueObjectSP valobj_sp);
149 
150             virtual bool
151             Update();
152 
153             virtual
154             ~NSArrayMSyntheticFrontEnd_1010 ();
155 
156         protected:
157             virtual lldb::addr_t
158             GetDataAddress ();
159 
160             virtual uint64_t
161             GetUsedCount ();
162 
163             virtual uint64_t
164             GetOffset ();
165 
166             virtual uint64_t
167             GetSize ();
168 
169         private:
170             DataDescriptor_32 *m_data_32;
171             DataDescriptor_64 *m_data_64;
172         };
173 
174         class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd
175         {
176         public:
177             NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
178 
179             virtual size_t
180             CalculateNumChildren ();
181 
182             virtual lldb::ValueObjectSP
183             GetChildAtIndex (size_t idx);
184 
185             virtual bool
186             Update();
187 
188             virtual bool
189             MightHaveChildren ();
190 
191             virtual size_t
192             GetIndexOfChildWithName (const ConstString &name);
193 
194             virtual
195             ~NSArrayISyntheticFrontEnd ();
196         private:
197             ExecutionContextRef m_exe_ctx_ref;
198             uint8_t m_ptr_size;
199             uint64_t m_items;
200             lldb::addr_t m_data_ptr;
201             CompilerType m_id_type;
202             std::vector<lldb::ValueObjectSP> m_children;
203         };
204 
205         class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd
206         {
207         public:
208             NSArray0SyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
209 
210             virtual size_t
211             CalculateNumChildren ();
212 
213             virtual lldb::ValueObjectSP
214             GetChildAtIndex (size_t idx);
215 
216             virtual bool
217             Update();
218 
219             virtual bool
220             MightHaveChildren ();
221 
222             virtual size_t
223             GetIndexOfChildWithName (const ConstString &name);
224 
225             virtual
226             ~NSArray0SyntheticFrontEnd ();
227         private:
228         };
229 
230         class NSArrayCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
231         {
232         public:
233             NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
234 
235             virtual size_t
236             CalculateNumChildren ();
237 
238             virtual lldb::ValueObjectSP
239             GetChildAtIndex (size_t idx);
240 
241             virtual bool
242             Update();
243 
244             virtual bool
245             MightHaveChildren ();
246 
247             virtual size_t
248             GetIndexOfChildWithName (const ConstString &name);
249 
250             virtual
251             ~NSArrayCodeRunningSyntheticFrontEnd ();
252         };
253     }
254 }
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::addr_t
484 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetDataAddress ()
485 {
486     if (!m_data_32 && !m_data_64)
487         return LLDB_INVALID_ADDRESS;
488     return m_data_32 ? m_data_32->_data :
489     m_data_64->_data;
490 }
491 
492 uint64_t
493 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetUsedCount ()
494 {
495     if (!m_data_32 && !m_data_64)
496         return 0;
497     return m_data_32 ? m_data_32->_used :
498     m_data_64->_used;
499 }
500 
501 uint64_t
502 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetOffset ()
503 {
504     if (!m_data_32 && !m_data_64)
505         return 0;
506     return m_data_32 ? m_data_32->_offset :
507     m_data_64->_offset;
508 }
509 
510 uint64_t
511 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetSize ()
512 {
513     if (!m_data_32 && !m_data_64)
514         return 0;
515     return m_data_32 ? m_data_32->_size :
516     m_data_64->_size;
517 }
518 
519 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::~NSArrayMSyntheticFrontEnd_109 ()
520 {
521     delete m_data_32;
522     m_data_32 = NULL;
523     delete m_data_64;
524     m_data_64 = NULL;
525 }
526 
527 lldb::addr_t
528 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetDataAddress ()
529 {
530     if (!m_data_32 && !m_data_64)
531         return LLDB_INVALID_ADDRESS;
532     return m_data_32 ? m_data_32->_data :
533     m_data_64->_data;
534 }
535 
536 uint64_t
537 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetUsedCount ()
538 {
539     if (!m_data_32 && !m_data_64)
540         return 0;
541     return m_data_32 ? m_data_32->_used :
542     m_data_64->_used;
543 }
544 
545 uint64_t
546 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetOffset ()
547 {
548     if (!m_data_32 && !m_data_64)
549         return 0;
550     return m_data_32 ? m_data_32->_offset :
551     m_data_64->_offset;
552 }
553 
554 uint64_t
555 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize ()
556 {
557     if (!m_data_32 && !m_data_64)
558         return 0;
559     return m_data_32 ? m_data_32->_size :
560     m_data_64->_size;
561 }
562 
563 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::~NSArrayMSyntheticFrontEnd_1010 ()
564 {
565     delete m_data_32;
566     m_data_32 = NULL;
567     delete m_data_64;
568     m_data_64 = NULL;
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 lldb_private::formatters::NSArrayISyntheticFrontEnd::~NSArrayISyntheticFrontEnd ()
591 {
592 }
593 
594 size_t
595 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
596 {
597     const char* item_name = name.GetCString();
598     uint32_t idx = ExtractIndexFromString(item_name);
599     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
600         return UINT32_MAX;
601     return idx;
602 }
603 
604 size_t
605 lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren ()
606 {
607     return m_items;
608 }
609 
610 bool
611 lldb_private::formatters::NSArrayISyntheticFrontEnd::Update()
612 {
613     m_ptr_size = 0;
614     m_items = 0;
615     m_data_ptr = 0;
616     m_children.clear();
617     ValueObjectSP valobj_sp = m_backend.GetSP();
618     if (!valobj_sp)
619         return false;
620     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
621     Error error;
622     error.Clear();
623     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
624     if (!process_sp)
625         return false;
626     m_ptr_size = process_sp->GetAddressByteSize();
627     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
628     m_items = process_sp->ReadPointerFromMemory(data_location, error);
629     if (error.Fail())
630         return false;
631     m_data_ptr = data_location+m_ptr_size;
632     return false;
633 }
634 
635 bool
636 lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren ()
637 {
638     return true;
639 }
640 
641 lldb::ValueObjectSP
642 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx)
643 {
644     if (idx >= CalculateNumChildren())
645         return lldb::ValueObjectSP();
646     lldb::addr_t object_at_idx = m_data_ptr;
647     object_at_idx += (idx * m_ptr_size);
648     ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
649     if (!process_sp)
650         return lldb::ValueObjectSP();
651     Error error;
652     if (error.Fail())
653         return lldb::ValueObjectSP();
654     StreamString idx_name;
655     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
656     lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(),
657                                                                  object_at_idx,
658                                                                  m_exe_ctx_ref,
659                                                                  m_id_type);
660     m_children.push_back(retval_sp);
661     return retval_sp;
662 }
663 
664 lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
665 SyntheticChildrenFrontEnd (*valobj_sp.get())
666 {
667 }
668 
669 lldb_private::formatters::NSArray0SyntheticFrontEnd::~NSArray0SyntheticFrontEnd ()
670 {
671 }
672 
673 size_t
674 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
675 {
676     return UINT32_MAX;
677 }
678 
679 size_t
680 lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren ()
681 {
682     return 0;
683 }
684 
685 bool
686 lldb_private::formatters::NSArray0SyntheticFrontEnd::Update()
687 {
688     return false;
689 }
690 
691 bool
692 lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren ()
693 {
694     return false;
695 }
696 
697 lldb::ValueObjectSP
698 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex (size_t idx)
699 {
700     return lldb::ValueObjectSP();
701 }
702 
703 SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
704 {
705     if (!valobj_sp)
706         return nullptr;
707 
708     lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
709     if (!process_sp)
710         return NULL;
711     AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
712     if (!runtime)
713         return NULL;
714 
715     CompilerType valobj_type(valobj_sp->GetCompilerType());
716     Flags flags(valobj_type.GetTypeInfo());
717 
718     if (flags.IsClear(eTypeIsPointer))
719     {
720         Error error;
721         valobj_sp = valobj_sp->AddressOf(error);
722         if (error.Fail() || !valobj_sp)
723             return NULL;
724     }
725 
726     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
727 
728     if (!descriptor.get() || !descriptor->IsValid())
729         return NULL;
730 
731     const char* class_name = descriptor->GetClassName().GetCString();
732 
733     if (!class_name || !*class_name)
734         return NULL;
735 
736     if (!strcmp(class_name,"__NSArrayI"))
737     {
738         return (new NSArrayISyntheticFrontEnd(valobj_sp));
739     }
740     else if (!strcmp(class_name,"__NSArray0"))
741     {
742         return (new NSArray0SyntheticFrontEnd(valobj_sp));
743     }
744     else if (!strcmp(class_name,"__NSArrayM"))
745     {
746         if (runtime->GetFoundationVersion() >= 1100)
747             return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp));
748         else
749             return (new NSArrayMSyntheticFrontEnd_109(valobj_sp));
750     }
751     else
752     {
753         return (new NSArrayCodeRunningSyntheticFrontEnd(valobj_sp));
754     }
755 }
756 
757 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
758 SyntheticChildrenFrontEnd(*valobj_sp.get())
759 {}
760 
761 size_t
762 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
763 {
764     uint64_t count = 0;
765     if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
766         return count;
767     return 0;
768 }
769 
770 lldb::ValueObjectSP
771 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
772 {
773     StreamString idx_name;
774     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
775     lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx);
776     if (valobj_sp)
777     {
778         valobj_sp->SetPreferredDisplayLanguage(m_backend.GetPreferredDisplayLanguage());
779         valobj_sp->SetName(ConstString(idx_name.GetData()));
780     }
781     return valobj_sp;
782 }
783 
784 bool
785 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::Update()
786 {
787     return false;
788 }
789 
790 bool
791 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::MightHaveChildren ()
792 {
793     return true;
794 }
795 
796 size_t
797 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
798 {
799     return 0;
800 }
801 
802 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::~NSArrayCodeRunningSyntheticFrontEnd ()
803 {}
804