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