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     } // namespace formatters
231 } // namespace lldb_private
232 
233 bool
234 lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
235 {
236     static ConstString g_TypeHint("NSArray");
237 
238     ProcessSP process_sp = valobj.GetProcessSP();
239     if (!process_sp)
240         return false;
241 
242     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
243 
244     if (!runtime)
245         return false;
246 
247     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
248 
249     if (!descriptor.get() || !descriptor->IsValid())
250         return false;
251 
252     uint32_t ptr_size = process_sp->GetAddressByteSize();
253 
254     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
255 
256     if (!valobj_addr)
257         return false;
258 
259     uint64_t value = 0;
260 
261     const char* class_name = descriptor->GetClassName().GetCString();
262 
263     if (!class_name || !*class_name)
264         return false;
265 
266     if (!strcmp(class_name,"__NSArrayI"))
267     {
268         Error error;
269         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
270         if (error.Fail())
271             return false;
272     }
273     else if (!strcmp(class_name,"__NSArrayM"))
274     {
275         Error error;
276         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
277         if (error.Fail())
278             return false;
279     }
280     else if (!strcmp(class_name,"__NSArray0"))
281     {
282         value = 0;
283     }
284     else if (!strcmp(class_name,"__NSCFArray"))
285     {
286         Error error;
287         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error);
288         if (error.Fail())
289             return false;
290     }
291     else
292             return false;
293 
294     std::string prefix,suffix;
295     if (Language* language = Language::FindPlugin(options.GetLanguage()))
296     {
297         if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
298         {
299             prefix.clear();
300             suffix.clear();
301         }
302     }
303 
304     stream.Printf("%s%" PRIu64 " %s%s%s",
305                   prefix.c_str(),
306                   value,
307                   "element",
308                   value == 1 ? "" : "s",
309                   suffix.c_str());
310     return true;
311 }
312 
313 lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
314 SyntheticChildrenFrontEnd(*valobj_sp),
315 m_exe_ctx_ref(),
316 m_ptr_size(8),
317 m_id_type(),
318 m_children()
319 {
320     if (valobj_sp)
321     {
322         clang::ASTContext *ast = valobj_sp->GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext()->getASTContext();
323         if (ast)
324             m_id_type = CompilerType(ast, ast->ObjCBuiltinIdTy);
325         if (valobj_sp->GetProcessSP())
326             m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
327     }
328 }
329 
330 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::NSArrayMSyntheticFrontEnd_109 (lldb::ValueObjectSP valobj_sp) :
331 NSArrayMSyntheticFrontEnd(valobj_sp),
332 m_data_32(NULL),
333 m_data_64(NULL)
334 {
335 }
336 
337 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::NSArrayMSyntheticFrontEnd_1010 (lldb::ValueObjectSP valobj_sp) :
338 NSArrayMSyntheticFrontEnd(valobj_sp),
339 m_data_32(NULL),
340 m_data_64(NULL)
341 {
342 }
343 
344 size_t
345 lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren ()
346 {
347     return GetUsedCount();
348 }
349 
350 lldb::ValueObjectSP
351 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
352 {
353     if (idx >= CalculateNumChildren())
354         return lldb::ValueObjectSP();
355     lldb::addr_t object_at_idx = GetDataAddress();
356     size_t pyhs_idx = idx;
357     pyhs_idx += GetOffset();
358     if (GetSize() <= pyhs_idx)
359         pyhs_idx -= GetSize();
360     object_at_idx += (pyhs_idx * m_ptr_size);
361     StreamString idx_name;
362     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
363     lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(),
364                                                                  object_at_idx,
365                                                                  m_exe_ctx_ref,
366                                                                  m_id_type);
367     m_children.push_back(retval_sp);
368     return retval_sp;
369 }
370 
371 bool
372 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::Update()
373 {
374     m_children.clear();
375     ValueObjectSP valobj_sp = m_backend.GetSP();
376     m_ptr_size = 0;
377     delete m_data_32;
378     m_data_32 = NULL;
379     delete m_data_64;
380     m_data_64 = NULL;
381     if (!valobj_sp)
382         return false;
383     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
384     Error error;
385     error.Clear();
386     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
387     if (!process_sp)
388         return false;
389     m_ptr_size = process_sp->GetAddressByteSize();
390     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
391     if (m_ptr_size == 4)
392     {
393         m_data_32 = new DataDescriptor_32();
394         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
395     }
396     else
397     {
398         m_data_64 = new DataDescriptor_64();
399         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
400     }
401     if (error.Fail())
402         return false;
403     return false;
404 }
405 
406 bool
407 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::Update()
408 {
409     m_children.clear();
410     ValueObjectSP valobj_sp = m_backend.GetSP();
411     m_ptr_size = 0;
412     delete m_data_32;
413     m_data_32 = NULL;
414     delete m_data_64;
415     m_data_64 = NULL;
416     if (!valobj_sp)
417         return false;
418     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
419     Error error;
420     error.Clear();
421     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
422     if (!process_sp)
423         return false;
424     m_ptr_size = process_sp->GetAddressByteSize();
425     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
426     if (m_ptr_size == 4)
427     {
428         m_data_32 = new DataDescriptor_32();
429         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
430     }
431     else
432     {
433         m_data_64 = new DataDescriptor_64();
434         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
435     }
436     if (error.Fail())
437         return false;
438     return false;
439 }
440 
441 bool
442 lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren ()
443 {
444     return true;
445 }
446 
447 size_t
448 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
449 {
450     const char* item_name = name.GetCString();
451     uint32_t idx = ExtractIndexFromString(item_name);
452     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
453         return UINT32_MAX;
454     return idx;
455 }
456 
457 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::~NSArrayMSyntheticFrontEnd_109()
458 {
459     delete m_data_32;
460     m_data_32 = NULL;
461     delete m_data_64;
462     m_data_64 = NULL;
463 }
464 
465 lldb::addr_t
466 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetDataAddress ()
467 {
468     if (!m_data_32 && !m_data_64)
469         return LLDB_INVALID_ADDRESS;
470     return m_data_32 ? m_data_32->_data :
471     m_data_64->_data;
472 }
473 
474 uint64_t
475 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetUsedCount ()
476 {
477     if (!m_data_32 && !m_data_64)
478         return 0;
479     return m_data_32 ? m_data_32->_used :
480     m_data_64->_used;
481 }
482 
483 uint64_t
484 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetOffset ()
485 {
486     if (!m_data_32 && !m_data_64)
487         return 0;
488     return m_data_32 ? m_data_32->_offset :
489     m_data_64->_offset;
490 }
491 
492 uint64_t
493 lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::GetSize ()
494 {
495     if (!m_data_32 && !m_data_64)
496         return 0;
497     return m_data_32 ? m_data_32->_size :
498     m_data_64->_size;
499 }
500 
501 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::~NSArrayMSyntheticFrontEnd_1010()
502 {
503     delete m_data_32;
504     m_data_32 = NULL;
505     delete m_data_64;
506     m_data_64 = NULL;
507 }
508 
509 lldb::addr_t
510 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetDataAddress ()
511 {
512     if (!m_data_32 && !m_data_64)
513         return LLDB_INVALID_ADDRESS;
514     return m_data_32 ? m_data_32->_data :
515     m_data_64->_data;
516 }
517 
518 uint64_t
519 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetUsedCount ()
520 {
521     if (!m_data_32 && !m_data_64)
522         return 0;
523     return m_data_32 ? m_data_32->_used :
524     m_data_64->_used;
525 }
526 
527 uint64_t
528 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetOffset ()
529 {
530     if (!m_data_32 && !m_data_64)
531         return 0;
532     return m_data_32 ? m_data_32->_offset :
533     m_data_64->_offset;
534 }
535 
536 uint64_t
537 lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize ()
538 {
539     if (!m_data_32 && !m_data_64)
540         return 0;
541     return m_data_32 ? m_data_32->_size :
542     m_data_64->_size;
543 }
544 
545 lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
546 SyntheticChildrenFrontEnd (*valobj_sp.get()),
547 m_exe_ctx_ref (),
548 m_ptr_size (8),
549 m_items (0),
550 m_data_ptr (0)
551 {
552     if (valobj_sp)
553     {
554         CompilerType type = valobj_sp->GetCompilerType();
555         if (type)
556         {
557             ClangASTContext *ast = valobj_sp->GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext();
558             if (ast)
559                 m_id_type = CompilerType(ast->getASTContext(), ast->getASTContext()->ObjCBuiltinIdTy);
560         }
561     }
562 }
563 
564 size_t
565 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
566 {
567     const char* item_name = name.GetCString();
568     uint32_t idx = ExtractIndexFromString(item_name);
569     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
570         return UINT32_MAX;
571     return idx;
572 }
573 
574 size_t
575 lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren ()
576 {
577     return m_items;
578 }
579 
580 bool
581 lldb_private::formatters::NSArrayISyntheticFrontEnd::Update()
582 {
583     m_ptr_size = 0;
584     m_items = 0;
585     m_data_ptr = 0;
586     m_children.clear();
587     ValueObjectSP valobj_sp = m_backend.GetSP();
588     if (!valobj_sp)
589         return false;
590     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
591     Error error;
592     error.Clear();
593     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
594     if (!process_sp)
595         return false;
596     m_ptr_size = process_sp->GetAddressByteSize();
597     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
598     m_items = process_sp->ReadPointerFromMemory(data_location, error);
599     if (error.Fail())
600         return false;
601     m_data_ptr = data_location+m_ptr_size;
602     return false;
603 }
604 
605 bool
606 lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren ()
607 {
608     return true;
609 }
610 
611 lldb::ValueObjectSP
612 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx)
613 {
614     if (idx >= CalculateNumChildren())
615         return lldb::ValueObjectSP();
616     lldb::addr_t object_at_idx = m_data_ptr;
617     object_at_idx += (idx * m_ptr_size);
618     ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
619     if (!process_sp)
620         return lldb::ValueObjectSP();
621     Error error;
622     if (error.Fail())
623         return lldb::ValueObjectSP();
624     StreamString idx_name;
625     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
626     lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(),
627                                                                  object_at_idx,
628                                                                  m_exe_ctx_ref,
629                                                                  m_id_type);
630     m_children.push_back(retval_sp);
631     return retval_sp;
632 }
633 
634 lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
635 SyntheticChildrenFrontEnd (*valobj_sp.get())
636 {
637 }
638 
639 size_t
640 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
641 {
642     return UINT32_MAX;
643 }
644 
645 size_t
646 lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren ()
647 {
648     return 0;
649 }
650 
651 bool
652 lldb_private::formatters::NSArray0SyntheticFrontEnd::Update()
653 {
654     return false;
655 }
656 
657 bool
658 lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren ()
659 {
660     return false;
661 }
662 
663 lldb::ValueObjectSP
664 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex (size_t idx)
665 {
666     return lldb::ValueObjectSP();
667 }
668 
669 SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
670 {
671     if (!valobj_sp)
672         return nullptr;
673 
674     lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
675     if (!process_sp)
676         return NULL;
677     AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
678     if (!runtime)
679         return NULL;
680 
681     CompilerType valobj_type(valobj_sp->GetCompilerType());
682     Flags flags(valobj_type.GetTypeInfo());
683 
684     if (flags.IsClear(eTypeIsPointer))
685     {
686         Error error;
687         valobj_sp = valobj_sp->AddressOf(error);
688         if (error.Fail() || !valobj_sp)
689             return NULL;
690     }
691 
692     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
693 
694     if (!descriptor.get() || !descriptor->IsValid())
695         return NULL;
696 
697     const char* class_name = descriptor->GetClassName().GetCString();
698 
699     if (!class_name || !*class_name)
700         return NULL;
701 
702     if (!strcmp(class_name,"__NSArrayI"))
703     {
704         return (new NSArrayISyntheticFrontEnd(valobj_sp));
705     }
706     else if (!strcmp(class_name,"__NSArray0"))
707     {
708         return (new NSArray0SyntheticFrontEnd(valobj_sp));
709     }
710     else if (!strcmp(class_name,"__NSArrayM"))
711     {
712         if (runtime->GetFoundationVersion() >= 1100)
713             return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp));
714         else
715             return (new NSArrayMSyntheticFrontEnd_109(valobj_sp));
716     }
717 
718     return nullptr;
719 }
720