]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Plugins/Language/ObjC/NSSet.cpp
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / source / Plugins / Language / ObjC / NSSet.cpp
1 //===-- NSSet.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 // Project includes
14 #include "NSSet.h"
15
16 #include "lldb/Core/DataBufferHeap.h"
17 #include "lldb/Core/Error.h"
18 #include "lldb/Core/Stream.h"
19 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Core/ValueObjectConstResult.h"
21 #include "lldb/DataFormatters/FormattersHelpers.h"
22 #include "lldb/Host/Endian.h"
23 #include "lldb/Symbol/ClangASTContext.h"
24 #include "lldb/Target/Language.h"
25 #include "lldb/Target/ObjCLanguageRuntime.h"
26 #include "lldb/Target/Target.h"
27
28 using namespace lldb;
29 using namespace lldb_private;
30 using namespace lldb_private::formatters;
31
32 std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
33 NSSet_Additionals::GetAdditionalSummaries() {
34   static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
35   return g_map;
36 }
37
38 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
39 NSSet_Additionals::GetAdditionalSynthetics() {
40   static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
41       g_map;
42   return g_map;
43 }
44
45 namespace lldb_private {
46 namespace formatters {
47 class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
48 public:
49   NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
50
51   ~NSSetISyntheticFrontEnd() override;
52
53   size_t CalculateNumChildren() override;
54
55   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
56
57   bool Update() override;
58
59   bool MightHaveChildren() override;
60
61   size_t GetIndexOfChildWithName(const ConstString &name) override;
62
63 private:
64   struct DataDescriptor_32 {
65     uint32_t _used : 26;
66     uint32_t _szidx : 6;
67   };
68
69   struct DataDescriptor_64 {
70     uint64_t _used : 58;
71     uint32_t _szidx : 6;
72   };
73
74   struct SetItemDescriptor {
75     lldb::addr_t item_ptr;
76     lldb::ValueObjectSP valobj_sp;
77   };
78
79   ExecutionContextRef m_exe_ctx_ref;
80   uint8_t m_ptr_size;
81   DataDescriptor_32 *m_data_32;
82   DataDescriptor_64 *m_data_64;
83   lldb::addr_t m_data_ptr;
84   std::vector<SetItemDescriptor> m_children;
85 };
86
87 class NSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
88 public:
89   NSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
90
91   ~NSSetMSyntheticFrontEnd() override;
92
93   size_t CalculateNumChildren() override;
94
95   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
96
97   bool Update() override;
98
99   bool MightHaveChildren() override;
100
101   size_t GetIndexOfChildWithName(const ConstString &name) override;
102
103 private:
104   struct DataDescriptor_32 {
105     uint32_t _used : 26;
106     uint32_t _size;
107     uint32_t _mutations;
108     uint32_t _objs_addr;
109   };
110
111   struct DataDescriptor_64 {
112     uint64_t _used : 58;
113     uint64_t _size;
114     uint64_t _mutations;
115     uint64_t _objs_addr;
116   };
117
118   struct SetItemDescriptor {
119     lldb::addr_t item_ptr;
120     lldb::ValueObjectSP valobj_sp;
121   };
122
123   ExecutionContextRef m_exe_ctx_ref;
124   uint8_t m_ptr_size;
125   DataDescriptor_32 *m_data_32;
126   DataDescriptor_64 *m_data_64;
127   std::vector<SetItemDescriptor> m_children;
128 };
129
130 class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
131 public:
132   NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
133
134   ~NSSetCodeRunningSyntheticFrontEnd() override;
135
136   size_t CalculateNumChildren() override;
137
138   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
139
140   bool Update() override;
141
142   bool MightHaveChildren() override;
143
144   size_t GetIndexOfChildWithName(const ConstString &name) override;
145 };
146 } // namespace formatters
147 } // namespace lldb_private
148
149 template <bool cf_style>
150 bool lldb_private::formatters::NSSetSummaryProvider(
151     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
152   static ConstString g_TypeHint("NSSet");
153
154   ProcessSP process_sp = valobj.GetProcessSP();
155   if (!process_sp)
156     return false;
157
158   ObjCLanguageRuntime *runtime =
159       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
160           lldb::eLanguageTypeObjC);
161
162   if (!runtime)
163     return false;
164
165   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
166       runtime->GetClassDescriptor(valobj));
167
168   if (!descriptor || !descriptor->IsValid())
169     return false;
170
171   uint32_t ptr_size = process_sp->GetAddressByteSize();
172   bool is_64bit = (ptr_size == 8);
173
174   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
175
176   if (!valobj_addr)
177     return false;
178
179   uint64_t value = 0;
180
181   ConstString class_name_cs = descriptor->GetClassName();
182   const char *class_name = class_name_cs.GetCString();
183
184   if (!class_name || !*class_name)
185     return false;
186
187   if (!strcmp(class_name, "__NSSetI")) {
188     Error error;
189     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
190                                                       ptr_size, 0, error);
191     if (error.Fail())
192       return false;
193     value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
194   } else if (!strcmp(class_name, "__NSSetM")) {
195     Error error;
196     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
197                                                       ptr_size, 0, error);
198     if (error.Fail())
199       return false;
200     value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
201   }
202   /*else if (!strcmp(class_name,"__NSCFSet"))
203    {
204    Error error;
205    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ?
206    20 : 12), 4, 0, error);
207    if (error.Fail())
208    return false;
209    if (is_64bit)
210    value &= ~0x1fff000000000000UL;
211    }
212    else if (!strcmp(class_name,"NSCountedSet"))
213    {
214    Error error;
215    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
216    ptr_size, 0, error);
217    if (error.Fail())
218    return false;
219    value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 :
220    12), 4, 0, error);
221    if (error.Fail())
222    return false;
223    if (is_64bit)
224    value &= ~0x1fff000000000000UL;
225    }*/
226   else {
227     auto &map(NSSet_Additionals::GetAdditionalSummaries());
228     auto iter = map.find(class_name_cs), end = map.end();
229     if (iter != end)
230       return iter->second(valobj, stream, options);
231     else
232       return false;
233   }
234
235   std::string prefix, suffix;
236   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
237     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
238                                             suffix)) {
239       prefix.clear();
240       suffix.clear();
241     }
242   }
243
244   stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
245                 value == 1 ? "" : "s", suffix.c_str());
246   return true;
247 }
248
249 SyntheticChildrenFrontEnd *
250 lldb_private::formatters::NSSetSyntheticFrontEndCreator(
251     CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
252   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
253   if (!process_sp)
254     return nullptr;
255   ObjCLanguageRuntime *runtime =
256       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
257           lldb::eLanguageTypeObjC);
258   if (!runtime)
259     return nullptr;
260
261   CompilerType valobj_type(valobj_sp->GetCompilerType());
262   Flags flags(valobj_type.GetTypeInfo());
263
264   if (flags.IsClear(eTypeIsPointer)) {
265     Error error;
266     valobj_sp = valobj_sp->AddressOf(error);
267     if (error.Fail() || !valobj_sp)
268       return nullptr;
269   }
270
271   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
272       runtime->GetClassDescriptor(*valobj_sp));
273
274   if (!descriptor || !descriptor->IsValid())
275     return nullptr;
276
277   ConstString class_name_cs = descriptor->GetClassName();
278   const char *class_name = class_name_cs.GetCString();
279
280   if (!class_name || !*class_name)
281     return nullptr;
282
283   if (!strcmp(class_name, "__NSSetI")) {
284     return (new NSSetISyntheticFrontEnd(valobj_sp));
285   } else if (!strcmp(class_name, "__NSSetM")) {
286     return (new NSSetMSyntheticFrontEnd(valobj_sp));
287   } else {
288     auto &map(NSSet_Additionals::GetAdditionalSynthetics());
289     auto iter = map.find(class_name_cs), end = map.end();
290     if (iter != end)
291       return iter->second(synth, valobj_sp);
292     return nullptr;
293   }
294 }
295
296 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(
297     lldb::ValueObjectSP valobj_sp)
298     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
299       m_data_32(nullptr), m_data_64(nullptr) {
300   if (valobj_sp)
301     Update();
302 }
303
304 lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {
305   delete m_data_32;
306   m_data_32 = nullptr;
307   delete m_data_64;
308   m_data_64 = nullptr;
309 }
310
311 size_t
312 lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(
313     const ConstString &name) {
314   const char *item_name = name.GetCString();
315   uint32_t idx = ExtractIndexFromString(item_name);
316   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
317     return UINT32_MAX;
318   return idx;
319 }
320
321 size_t
322 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {
323   if (!m_data_32 && !m_data_64)
324     return 0;
325   return (m_data_32 ? m_data_32->_used : m_data_64->_used);
326 }
327
328 bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
329   m_children.clear();
330   delete m_data_32;
331   m_data_32 = nullptr;
332   delete m_data_64;
333   m_data_64 = nullptr;
334   m_ptr_size = 0;
335   ValueObjectSP valobj_sp = m_backend.GetSP();
336   if (!valobj_sp)
337     return false;
338   if (!valobj_sp)
339     return false;
340   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
341   Error error;
342   if (valobj_sp->IsPointerType()) {
343     valobj_sp = valobj_sp->Dereference(error);
344     if (error.Fail() || !valobj_sp)
345       return false;
346   }
347   error.Clear();
348   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
349   if (!process_sp)
350     return false;
351   m_ptr_size = process_sp->GetAddressByteSize();
352   uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
353   if (m_ptr_size == 4) {
354     m_data_32 = new DataDescriptor_32();
355     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
356                            error);
357   } else {
358     m_data_64 = new DataDescriptor_64();
359     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
360                            error);
361   }
362   if (error.Fail())
363     return false;
364   m_data_ptr = data_location + m_ptr_size;
365   return false;
366 }
367
368 bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() {
369   return true;
370 }
371
372 lldb::ValueObjectSP
373 lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) {
374   uint32_t num_children = CalculateNumChildren();
375
376   if (idx >= num_children)
377     return lldb::ValueObjectSP();
378
379   ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
380   if (!process_sp)
381     return lldb::ValueObjectSP();
382
383   if (m_children.empty()) {
384     // do the scan phase
385     lldb::addr_t obj_at_idx = 0;
386
387     uint32_t tries = 0;
388     uint32_t test_idx = 0;
389
390     while (tries < num_children) {
391       obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
392       if (!process_sp)
393         return lldb::ValueObjectSP();
394       Error error;
395       obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
396       if (error.Fail())
397         return lldb::ValueObjectSP();
398
399       test_idx++;
400
401       if (!obj_at_idx)
402         continue;
403       tries++;
404
405       SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
406
407       m_children.push_back(descriptor);
408     }
409   }
410
411   if (idx >= m_children.size()) // should never happen
412     return lldb::ValueObjectSP();
413
414   SetItemDescriptor &set_item = m_children[idx];
415   if (!set_item.valobj_sp) {
416     auto ptr_size = process_sp->GetAddressByteSize();
417     DataBufferHeap buffer(ptr_size, 0);
418     switch (ptr_size) {
419     case 0: // architecture has no clue?? - fail
420       return lldb::ValueObjectSP();
421     case 4:
422       *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
423       break;
424     case 8:
425       *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
426       break;
427     default:
428       assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
429     }
430     StreamString idx_name;
431     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
432
433     DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
434                        process_sp->GetByteOrder(),
435                        process_sp->GetAddressByteSize());
436
437     set_item.valobj_sp = CreateValueObjectFromData(
438         idx_name.GetString(), data, m_exe_ctx_ref,
439         m_backend.GetCompilerType().GetBasicTypeFromAST(
440             lldb::eBasicTypeObjCID));
441   }
442   return set_item.valobj_sp;
443 }
444
445 lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd(
446     lldb::ValueObjectSP valobj_sp)
447     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
448       m_data_32(nullptr), m_data_64(nullptr) {
449   if (valobj_sp)
450     Update();
451 }
452
453 lldb_private::formatters::NSSetMSyntheticFrontEnd::~NSSetMSyntheticFrontEnd() {
454   delete m_data_32;
455   m_data_32 = nullptr;
456   delete m_data_64;
457   m_data_64 = nullptr;
458 }
459
460 size_t
461 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetIndexOfChildWithName(
462     const ConstString &name) {
463   const char *item_name = name.GetCString();
464   uint32_t idx = ExtractIndexFromString(item_name);
465   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
466     return UINT32_MAX;
467   return idx;
468 }
469
470 size_t
471 lldb_private::formatters::NSSetMSyntheticFrontEnd::CalculateNumChildren() {
472   if (!m_data_32 && !m_data_64)
473     return 0;
474   return (m_data_32 ? m_data_32->_used : m_data_64->_used);
475 }
476
477 bool lldb_private::formatters::NSSetMSyntheticFrontEnd::Update() {
478   m_children.clear();
479   ValueObjectSP valobj_sp = m_backend.GetSP();
480   m_ptr_size = 0;
481   delete m_data_32;
482   m_data_32 = nullptr;
483   delete m_data_64;
484   m_data_64 = nullptr;
485   if (!valobj_sp)
486     return false;
487   if (!valobj_sp)
488     return false;
489   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
490   Error error;
491   if (valobj_sp->IsPointerType()) {
492     valobj_sp = valobj_sp->Dereference(error);
493     if (error.Fail() || !valobj_sp)
494       return false;
495   }
496   error.Clear();
497   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
498   if (!process_sp)
499     return false;
500   m_ptr_size = process_sp->GetAddressByteSize();
501   uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
502   if (m_ptr_size == 4) {
503     m_data_32 = new DataDescriptor_32();
504     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
505                            error);
506   } else {
507     m_data_64 = new DataDescriptor_64();
508     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
509                            error);
510   }
511   if (error.Fail())
512     return false;
513   return false;
514 }
515
516 bool lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren() {
517   return true;
518 }
519
520 lldb::ValueObjectSP
521 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
522   lldb::addr_t m_objs_addr =
523       (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
524
525   uint32_t num_children = CalculateNumChildren();
526
527   if (idx >= num_children)
528     return lldb::ValueObjectSP();
529
530   ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
531   if (!process_sp)
532     return lldb::ValueObjectSP();
533
534   if (m_children.empty()) {
535     // do the scan phase
536     lldb::addr_t obj_at_idx = 0;
537
538     uint32_t tries = 0;
539     uint32_t test_idx = 0;
540
541     while (tries < num_children) {
542       obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
543       if (!process_sp)
544         return lldb::ValueObjectSP();
545       Error error;
546       obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
547       if (error.Fail())
548         return lldb::ValueObjectSP();
549
550       test_idx++;
551
552       if (!obj_at_idx)
553         continue;
554       tries++;
555
556       SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
557
558       m_children.push_back(descriptor);
559     }
560   }
561
562   if (idx >= m_children.size()) // should never happen
563     return lldb::ValueObjectSP();
564
565   SetItemDescriptor &set_item = m_children[idx];
566   if (!set_item.valobj_sp) {
567     auto ptr_size = process_sp->GetAddressByteSize();
568     DataBufferHeap buffer(ptr_size, 0);
569     switch (ptr_size) {
570     case 0: // architecture has no clue?? - fail
571       return lldb::ValueObjectSP();
572     case 4:
573       *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
574       break;
575     case 8:
576       *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
577       break;
578     default:
579       assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
580     }
581     StreamString idx_name;
582     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
583
584     DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
585                        process_sp->GetByteOrder(),
586                        process_sp->GetAddressByteSize());
587
588     set_item.valobj_sp = CreateValueObjectFromData(
589         idx_name.GetString(), data, m_exe_ctx_ref,
590         m_backend.GetCompilerType().GetBasicTypeFromAST(
591             lldb::eBasicTypeObjCID));
592   }
593   return set_item.valobj_sp;
594 }
595
596 template bool lldb_private::formatters::NSSetSummaryProvider<true>(
597     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
598
599 template bool lldb_private::formatters::NSSetSummaryProvider<false>(
600     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);