xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- NSSet.cpp ---------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "NSSet.h"
105ffd83dbSDimitry Andric #include "CFBasicHash.h"
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
135ffd83dbSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
140b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
150b57cec5SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h"
160b57cec5SDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h"
170b57cec5SDimitry Andric #include "lldb/Target/Language.h"
180b57cec5SDimitry Andric #include "lldb/Target/Target.h"
190b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
200b57cec5SDimitry Andric #include "lldb/Utility/Endian.h"
210b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
220b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric using namespace lldb;
250b57cec5SDimitry Andric using namespace lldb_private;
260b57cec5SDimitry Andric using namespace lldb_private::formatters;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
290b57cec5SDimitry Andric NSSet_Additionals::GetAdditionalSummaries() {
300b57cec5SDimitry Andric   static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
310b57cec5SDimitry Andric   return g_map;
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
350b57cec5SDimitry Andric NSSet_Additionals::GetAdditionalSynthetics() {
360b57cec5SDimitry Andric   static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
370b57cec5SDimitry Andric       g_map;
380b57cec5SDimitry Andric   return g_map;
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric namespace lldb_private {
420b57cec5SDimitry Andric namespace formatters {
430b57cec5SDimitry Andric class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
440b57cec5SDimitry Andric public:
450b57cec5SDimitry Andric   NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   ~NSSetISyntheticFrontEnd() override;
480b57cec5SDimitry Andric 
49*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
500b57cec5SDimitry Andric 
51*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
520b57cec5SDimitry Andric 
53*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   bool MightHaveChildren() override;
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric private:
600b57cec5SDimitry Andric   struct DataDescriptor_32 {
610b57cec5SDimitry Andric     uint32_t _used : 26;
620b57cec5SDimitry Andric     uint32_t _szidx : 6;
630b57cec5SDimitry Andric   };
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   struct DataDescriptor_64 {
660b57cec5SDimitry Andric     uint64_t _used : 58;
670b57cec5SDimitry Andric     uint32_t _szidx : 6;
680b57cec5SDimitry Andric   };
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   struct SetItemDescriptor {
710b57cec5SDimitry Andric     lldb::addr_t item_ptr;
720b57cec5SDimitry Andric     lldb::ValueObjectSP valobj_sp;
730b57cec5SDimitry Andric   };
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   ExecutionContextRef m_exe_ctx_ref;
7681ad6265SDimitry Andric   uint8_t m_ptr_size = 8;
7781ad6265SDimitry Andric   DataDescriptor_32 *m_data_32 = nullptr;
7881ad6265SDimitry Andric   DataDescriptor_64 *m_data_64 = nullptr;
79fcaf7f86SDimitry Andric   lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;
800b57cec5SDimitry Andric   std::vector<SetItemDescriptor> m_children;
810b57cec5SDimitry Andric };
820b57cec5SDimitry Andric 
835ffd83dbSDimitry Andric class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
845ffd83dbSDimitry Andric public:
855ffd83dbSDimitry Andric   NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
865ffd83dbSDimitry Andric 
87*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
885ffd83dbSDimitry Andric 
89*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
905ffd83dbSDimitry Andric 
91*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
925ffd83dbSDimitry Andric 
935ffd83dbSDimitry Andric   bool MightHaveChildren() override;
945ffd83dbSDimitry Andric 
955ffd83dbSDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
965ffd83dbSDimitry Andric 
975ffd83dbSDimitry Andric private:
985ffd83dbSDimitry Andric   struct SetItemDescriptor {
995ffd83dbSDimitry Andric     lldb::addr_t item_ptr;
1005ffd83dbSDimitry Andric     lldb::ValueObjectSP valobj_sp;
1015ffd83dbSDimitry Andric   };
1025ffd83dbSDimitry Andric 
1035ffd83dbSDimitry Andric   ExecutionContextRef m_exe_ctx_ref;
10481ad6265SDimitry Andric   uint8_t m_ptr_size = 8;
10581ad6265SDimitry Andric   lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
1065ffd83dbSDimitry Andric 
1075ffd83dbSDimitry Andric   CFBasicHash m_hashtable;
1085ffd83dbSDimitry Andric 
1095ffd83dbSDimitry Andric   CompilerType m_pair_type;
1105ffd83dbSDimitry Andric   std::vector<SetItemDescriptor> m_children;
1115ffd83dbSDimitry Andric };
1125ffd83dbSDimitry Andric 
1130b57cec5SDimitry Andric template <typename D32, typename D64>
1140b57cec5SDimitry Andric class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
1150b57cec5SDimitry Andric public:
1160b57cec5SDimitry Andric   GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   ~GenericNSSetMSyntheticFrontEnd() override;
1190b57cec5SDimitry Andric 
120*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
1210b57cec5SDimitry Andric 
122*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
1230b57cec5SDimitry Andric 
124*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   bool MightHaveChildren() override;
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric private:
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   struct SetItemDescriptor {
1330b57cec5SDimitry Andric     lldb::addr_t item_ptr;
1340b57cec5SDimitry Andric     lldb::ValueObjectSP valobj_sp;
1350b57cec5SDimitry Andric   };
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   ExecutionContextRef m_exe_ctx_ref;
13881ad6265SDimitry Andric   uint8_t m_ptr_size = 8;
1390b57cec5SDimitry Andric   D32 *m_data_32;
1400b57cec5SDimitry Andric   D64 *m_data_64;
1410b57cec5SDimitry Andric   std::vector<SetItemDescriptor> m_children;
1420b57cec5SDimitry Andric };
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric namespace Foundation1300 {
1450b57cec5SDimitry Andric   struct DataDescriptor_32 {
1460b57cec5SDimitry Andric     uint32_t _used : 26;
1470b57cec5SDimitry Andric     uint32_t _size;
1480b57cec5SDimitry Andric     uint32_t _mutations;
1490b57cec5SDimitry Andric     uint32_t _objs_addr;
1500b57cec5SDimitry Andric   };
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   struct DataDescriptor_64 {
1530b57cec5SDimitry Andric     uint64_t _used : 58;
1540b57cec5SDimitry Andric     uint64_t _size;
1550b57cec5SDimitry Andric     uint64_t _mutations;
1560b57cec5SDimitry Andric     uint64_t _objs_addr;
1570b57cec5SDimitry Andric   };
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   using NSSetMSyntheticFrontEnd =
1600b57cec5SDimitry Andric       GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric namespace Foundation1428 {
1640b57cec5SDimitry Andric   struct DataDescriptor_32 {
1650b57cec5SDimitry Andric     uint32_t _used : 26;
1660b57cec5SDimitry Andric     uint32_t _size;
1670b57cec5SDimitry Andric     uint32_t _objs_addr;
1680b57cec5SDimitry Andric     uint32_t _mutations;
1690b57cec5SDimitry Andric   };
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   struct DataDescriptor_64 {
1720b57cec5SDimitry Andric     uint64_t _used : 58;
1730b57cec5SDimitry Andric     uint64_t _size;
1740b57cec5SDimitry Andric     uint64_t _objs_addr;
1750b57cec5SDimitry Andric     uint64_t _mutations;
1760b57cec5SDimitry Andric   };
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   using NSSetMSyntheticFrontEnd =
1790b57cec5SDimitry Andric       GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric namespace Foundation1437 {
1830b57cec5SDimitry Andric   struct DataDescriptor_32 {
1840b57cec5SDimitry Andric     uint32_t _cow;
1850b57cec5SDimitry Andric     // __table storage
1860b57cec5SDimitry Andric     uint32_t _objs_addr;
1870b57cec5SDimitry Andric     uint32_t _muts;
1880b57cec5SDimitry Andric     uint32_t _used : 26;
1890b57cec5SDimitry Andric     uint32_t _szidx : 6;
1900b57cec5SDimitry Andric   };
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   struct DataDescriptor_64 {
1930b57cec5SDimitry Andric     uint64_t _cow;
1940b57cec5SDimitry Andric     // __Table storage
1950b57cec5SDimitry Andric     uint64_t _objs_addr;
1960b57cec5SDimitry Andric     uint32_t _muts;
1970b57cec5SDimitry Andric     uint32_t _used : 26;
1980b57cec5SDimitry Andric     uint32_t _szidx : 6;
1990b57cec5SDimitry Andric   };
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   using NSSetMSyntheticFrontEnd =
2020b57cec5SDimitry Andric       GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   template <typename DD>
2050b57cec5SDimitry Andric   uint64_t
2060b57cec5SDimitry Andric   __NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr,
2070b57cec5SDimitry Andric                     Status &error) {
2080b57cec5SDimitry Andric     const lldb::addr_t start_of_descriptor =
2090b57cec5SDimitry Andric         valobj_addr + process.GetAddressByteSize();
2100b57cec5SDimitry Andric     DD descriptor = DD();
2110b57cec5SDimitry Andric     process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
2120b57cec5SDimitry Andric                        error);
2130b57cec5SDimitry Andric     if (error.Fail()) {
2140b57cec5SDimitry Andric       return 0;
2150b57cec5SDimitry Andric     }
2160b57cec5SDimitry Andric     return descriptor._used;
2170b57cec5SDimitry Andric   }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric   uint64_t
2200b57cec5SDimitry Andric   __NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
2210b57cec5SDimitry Andric                Status &error) {
2220b57cec5SDimitry Andric     if (process.GetAddressByteSize() == 4) {
2230b57cec5SDimitry Andric       return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error);
2240b57cec5SDimitry Andric     } else {
2250b57cec5SDimitry Andric       return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error);
2260b57cec5SDimitry Andric     }
2270b57cec5SDimitry Andric   }
2280b57cec5SDimitry Andric }
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
2310b57cec5SDimitry Andric public:
2320b57cec5SDimitry Andric   NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   ~NSSetCodeRunningSyntheticFrontEnd() override;
2350b57cec5SDimitry Andric 
236*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override;
2370b57cec5SDimitry Andric 
238*0fca6ea1SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
2390b57cec5SDimitry Andric 
240*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   bool MightHaveChildren() override;
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override;
2450b57cec5SDimitry Andric };
2460b57cec5SDimitry Andric } // namespace formatters
2470b57cec5SDimitry Andric } // namespace lldb_private
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric template <bool cf_style>
2500b57cec5SDimitry Andric bool lldb_private::formatters::NSSetSummaryProvider(
2510b57cec5SDimitry Andric     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
25206c3fb27SDimitry Andric   static constexpr llvm::StringLiteral g_TypeHint("NSSet");
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   ProcessSP process_sp = valobj.GetProcessSP();
2550b57cec5SDimitry Andric   if (!process_sp)
2560b57cec5SDimitry Andric     return false;
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   if (!runtime)
2610b57cec5SDimitry Andric     return false;
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
2640b57cec5SDimitry Andric       runtime->GetClassDescriptor(valobj));
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric   if (!descriptor || !descriptor->IsValid())
2670b57cec5SDimitry Andric     return false;
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   uint32_t ptr_size = process_sp->GetAddressByteSize();
2700b57cec5SDimitry Andric   bool is_64bit = (ptr_size == 8);
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   if (!valobj_addr)
2750b57cec5SDimitry Andric     return false;
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric   uint64_t value = 0;
2780b57cec5SDimitry Andric 
2795ffd83dbSDimitry Andric   ConstString class_name(descriptor->GetClassName());
2800b57cec5SDimitry Andric 
2815ffd83dbSDimitry Andric   static const ConstString g_SetI("__NSSetI");
2825ffd83dbSDimitry Andric   static const ConstString g_OrderedSetI("__NSOrderedSetI");
2835ffd83dbSDimitry Andric   static const ConstString g_SetM("__NSSetM");
2845ffd83dbSDimitry Andric   static const ConstString g_SetCF("__NSCFSet");
2855ffd83dbSDimitry Andric   static const ConstString g_SetCFRef("CFSetRef");
2865ffd83dbSDimitry Andric 
2875ffd83dbSDimitry Andric   if (class_name.IsEmpty())
2880b57cec5SDimitry Andric     return false;
2890b57cec5SDimitry Andric 
2905ffd83dbSDimitry Andric   if (class_name == g_SetI || class_name == g_OrderedSetI) {
2910b57cec5SDimitry Andric     Status error;
2920b57cec5SDimitry Andric     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
2930b57cec5SDimitry Andric                                                       ptr_size, 0, error);
2940b57cec5SDimitry Andric     if (error.Fail())
2950b57cec5SDimitry Andric       return false;
2960b57cec5SDimitry Andric     value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
2975ffd83dbSDimitry Andric   } else if (class_name == g_SetM) {
2980b57cec5SDimitry Andric     AppleObjCRuntime *apple_runtime =
2990b57cec5SDimitry Andric         llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
3000b57cec5SDimitry Andric     Status error;
3010b57cec5SDimitry Andric     if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
3020b57cec5SDimitry Andric       value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error);
3030b57cec5SDimitry Andric     } else {
3040b57cec5SDimitry Andric       value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
3050b57cec5SDimitry Andric                                                         ptr_size, 0, error);
3060b57cec5SDimitry Andric       value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
3070b57cec5SDimitry Andric     }
3080b57cec5SDimitry Andric     if (error.Fail())
3090b57cec5SDimitry Andric       return false;
3105ffd83dbSDimitry Andric   } else if (class_name == g_SetCF || class_name == g_SetCFRef) {
3115ffd83dbSDimitry Andric     ExecutionContext exe_ctx(process_sp);
3125ffd83dbSDimitry Andric     CFBasicHash cfbh;
3135ffd83dbSDimitry Andric     if (!cfbh.Update(valobj_addr, exe_ctx))
3145ffd83dbSDimitry Andric       return false;
3155ffd83dbSDimitry Andric     value = cfbh.GetCount();
3160b57cec5SDimitry Andric   } else {
3170b57cec5SDimitry Andric     auto &map(NSSet_Additionals::GetAdditionalSummaries());
3185ffd83dbSDimitry Andric     auto iter = map.find(class_name), end = map.end();
3190b57cec5SDimitry Andric     if (iter != end)
3200b57cec5SDimitry Andric       return iter->second(valobj, stream, options);
3210b57cec5SDimitry Andric     else
3220b57cec5SDimitry Andric       return false;
3230b57cec5SDimitry Andric   }
3240b57cec5SDimitry Andric 
32506c3fb27SDimitry Andric   llvm::StringRef prefix, suffix;
32606c3fb27SDimitry Andric   if (Language *language = Language::FindPlugin(options.GetLanguage()))
32706c3fb27SDimitry Andric     std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
3280b57cec5SDimitry Andric 
32906c3fb27SDimitry Andric   stream << prefix;
33006c3fb27SDimitry Andric   stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");
33106c3fb27SDimitry Andric   stream << suffix;
3320b57cec5SDimitry Andric   return true;
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric SyntheticChildrenFrontEnd *
3360b57cec5SDimitry Andric lldb_private::formatters::NSSetSyntheticFrontEndCreator(
3370b57cec5SDimitry Andric     CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
3380b57cec5SDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
3390b57cec5SDimitry Andric   if (!process_sp)
3400b57cec5SDimitry Andric     return nullptr;
3410b57cec5SDimitry Andric   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
3420b57cec5SDimitry Andric   if (!runtime)
3430b57cec5SDimitry Andric     return nullptr;
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   CompilerType valobj_type(valobj_sp->GetCompilerType());
3460b57cec5SDimitry Andric   Flags flags(valobj_type.GetTypeInfo());
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric   if (flags.IsClear(eTypeIsPointer)) {
3490b57cec5SDimitry Andric     Status error;
3500b57cec5SDimitry Andric     valobj_sp = valobj_sp->AddressOf(error);
3510b57cec5SDimitry Andric     if (error.Fail() || !valobj_sp)
3520b57cec5SDimitry Andric       return nullptr;
3530b57cec5SDimitry Andric   }
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
3560b57cec5SDimitry Andric       runtime->GetClassDescriptor(*valobj_sp));
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric   if (!descriptor || !descriptor->IsValid())
3590b57cec5SDimitry Andric     return nullptr;
3600b57cec5SDimitry Andric 
3615ffd83dbSDimitry Andric   ConstString class_name = descriptor->GetClassName();
3620b57cec5SDimitry Andric 
3635ffd83dbSDimitry Andric   static const ConstString g_SetI("__NSSetI");
3645ffd83dbSDimitry Andric   static const ConstString g_OrderedSetI("__NSOrderedSetI");
3655ffd83dbSDimitry Andric   static const ConstString g_SetM("__NSSetM");
3665ffd83dbSDimitry Andric   static const ConstString g_SetCF("__NSCFSet");
3675ffd83dbSDimitry Andric   static const ConstString g_SetCFRef("CFSetRef");
3685ffd83dbSDimitry Andric 
3695ffd83dbSDimitry Andric   if (class_name.IsEmpty())
3700b57cec5SDimitry Andric     return nullptr;
3710b57cec5SDimitry Andric 
3725ffd83dbSDimitry Andric   if (class_name == g_SetI || class_name == g_OrderedSetI) {
3730b57cec5SDimitry Andric     return (new NSSetISyntheticFrontEnd(valobj_sp));
3745ffd83dbSDimitry Andric   } else if (class_name == g_SetM) {
3750b57cec5SDimitry Andric     AppleObjCRuntime *apple_runtime =
3760b57cec5SDimitry Andric         llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
3770b57cec5SDimitry Andric     if (apple_runtime) {
3780b57cec5SDimitry Andric       if (apple_runtime->GetFoundationVersion() >= 1437)
3790b57cec5SDimitry Andric         return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp));
3800b57cec5SDimitry Andric       else if (apple_runtime->GetFoundationVersion() >= 1428)
3810b57cec5SDimitry Andric         return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp));
3820b57cec5SDimitry Andric       else
3830b57cec5SDimitry Andric         return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
3840b57cec5SDimitry Andric     } else {
3850b57cec5SDimitry Andric       return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
3860b57cec5SDimitry Andric     }
3875ffd83dbSDimitry Andric   } else if (class_name == g_SetCF || class_name == g_SetCFRef) {
3885ffd83dbSDimitry Andric     return (new NSCFSetSyntheticFrontEnd(valobj_sp));
3890b57cec5SDimitry Andric   } else {
3900b57cec5SDimitry Andric     auto &map(NSSet_Additionals::GetAdditionalSynthetics());
3915ffd83dbSDimitry Andric     auto iter = map.find(class_name), end = map.end();
3920b57cec5SDimitry Andric     if (iter != end)
3930b57cec5SDimitry Andric       return iter->second(synth, valobj_sp);
3940b57cec5SDimitry Andric     return nullptr;
3950b57cec5SDimitry Andric   }
3960b57cec5SDimitry Andric }
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(
3990b57cec5SDimitry Andric     lldb::ValueObjectSP valobj_sp)
40081ad6265SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref() {
4010b57cec5SDimitry Andric   if (valobj_sp)
4020b57cec5SDimitry Andric     Update();
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {
4060b57cec5SDimitry Andric   delete m_data_32;
4070b57cec5SDimitry Andric   m_data_32 = nullptr;
4080b57cec5SDimitry Andric   delete m_data_64;
4090b57cec5SDimitry Andric   m_data_64 = nullptr;
4100b57cec5SDimitry Andric }
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric size_t
4130b57cec5SDimitry Andric lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(
4140b57cec5SDimitry Andric     ConstString name) {
4150b57cec5SDimitry Andric   const char *item_name = name.GetCString();
4160b57cec5SDimitry Andric   uint32_t idx = ExtractIndexFromString(item_name);
417*0fca6ea1SDimitry Andric   if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
4180b57cec5SDimitry Andric     return UINT32_MAX;
4190b57cec5SDimitry Andric   return idx;
4200b57cec5SDimitry Andric }
4210b57cec5SDimitry Andric 
422*0fca6ea1SDimitry Andric llvm::Expected<uint32_t>
4230b57cec5SDimitry Andric lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {
4240b57cec5SDimitry Andric   if (!m_data_32 && !m_data_64)
4250b57cec5SDimitry Andric     return 0;
4260b57cec5SDimitry Andric   return (m_data_32 ? m_data_32->_used : m_data_64->_used);
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric 
429*0fca6ea1SDimitry Andric lldb::ChildCacheState
430*0fca6ea1SDimitry Andric lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
4310b57cec5SDimitry Andric   m_children.clear();
4320b57cec5SDimitry Andric   delete m_data_32;
4330b57cec5SDimitry Andric   m_data_32 = nullptr;
4340b57cec5SDimitry Andric   delete m_data_64;
4350b57cec5SDimitry Andric   m_data_64 = nullptr;
4360b57cec5SDimitry Andric   m_ptr_size = 0;
4370b57cec5SDimitry Andric   ValueObjectSP valobj_sp = m_backend.GetSP();
4380b57cec5SDimitry Andric   if (!valobj_sp)
439*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
4400b57cec5SDimitry Andric   if (!valobj_sp)
441*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
4420b57cec5SDimitry Andric   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
4430b57cec5SDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
4440b57cec5SDimitry Andric   if (!process_sp)
445*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
4460b57cec5SDimitry Andric   m_ptr_size = process_sp->GetAddressByteSize();
447fe6060f1SDimitry Andric   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
448fe6060f1SDimitry Andric   Status error;
4490b57cec5SDimitry Andric   if (m_ptr_size == 4) {
4500b57cec5SDimitry Andric     m_data_32 = new DataDescriptor_32();
4510b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
4520b57cec5SDimitry Andric                            error);
4530b57cec5SDimitry Andric   } else {
4540b57cec5SDimitry Andric     m_data_64 = new DataDescriptor_64();
4550b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
4560b57cec5SDimitry Andric                            error);
4570b57cec5SDimitry Andric   }
4580b57cec5SDimitry Andric   if (error.Fail())
459*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
4600b57cec5SDimitry Andric   m_data_ptr = data_location + m_ptr_size;
461*0fca6ea1SDimitry Andric   return lldb::ChildCacheState::eReuse;
4620b57cec5SDimitry Andric }
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() {
4650b57cec5SDimitry Andric   return true;
4660b57cec5SDimitry Andric }
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric lldb::ValueObjectSP
469*0fca6ea1SDimitry Andric lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(
470*0fca6ea1SDimitry Andric     uint32_t idx) {
471*0fca6ea1SDimitry Andric   uint32_t num_children = CalculateNumChildrenIgnoringErrors();
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric   if (idx >= num_children)
4740b57cec5SDimitry Andric     return lldb::ValueObjectSP();
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
4770b57cec5SDimitry Andric   if (!process_sp)
4780b57cec5SDimitry Andric     return lldb::ValueObjectSP();
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric   if (m_children.empty()) {
4810b57cec5SDimitry Andric     // do the scan phase
4820b57cec5SDimitry Andric     lldb::addr_t obj_at_idx = 0;
4830b57cec5SDimitry Andric 
4840b57cec5SDimitry Andric     uint32_t tries = 0;
4850b57cec5SDimitry Andric     uint32_t test_idx = 0;
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric     while (tries < num_children) {
4880b57cec5SDimitry Andric       obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
4890b57cec5SDimitry Andric       if (!process_sp)
4900b57cec5SDimitry Andric         return lldb::ValueObjectSP();
4910b57cec5SDimitry Andric       Status error;
4920b57cec5SDimitry Andric       obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
4930b57cec5SDimitry Andric       if (error.Fail())
4940b57cec5SDimitry Andric         return lldb::ValueObjectSP();
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric       test_idx++;
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric       if (!obj_at_idx)
4990b57cec5SDimitry Andric         continue;
5000b57cec5SDimitry Andric       tries++;
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric       SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric       m_children.push_back(descriptor);
5050b57cec5SDimitry Andric     }
5060b57cec5SDimitry Andric   }
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric   if (idx >= m_children.size()) // should never happen
5090b57cec5SDimitry Andric     return lldb::ValueObjectSP();
5100b57cec5SDimitry Andric 
5110b57cec5SDimitry Andric   SetItemDescriptor &set_item = m_children[idx];
5120b57cec5SDimitry Andric   if (!set_item.valobj_sp) {
5130b57cec5SDimitry Andric     auto ptr_size = process_sp->GetAddressByteSize();
5140b57cec5SDimitry Andric     DataBufferHeap buffer(ptr_size, 0);
5150b57cec5SDimitry Andric     switch (ptr_size) {
5165ffd83dbSDimitry Andric     case 0: // architecture has no clue - fail
5170b57cec5SDimitry Andric       return lldb::ValueObjectSP();
5180b57cec5SDimitry Andric     case 4:
5195ffd83dbSDimitry Andric       *reinterpret_cast<uint32_t *>(buffer.GetBytes()) =
5205ffd83dbSDimitry Andric           static_cast<uint32_t>(set_item.item_ptr);
5210b57cec5SDimitry Andric       break;
5220b57cec5SDimitry Andric     case 8:
5235ffd83dbSDimitry Andric       *reinterpret_cast<uint64_t *>(buffer.GetBytes()) =
5245ffd83dbSDimitry Andric           static_cast<uint64_t>(set_item.item_ptr);
5250b57cec5SDimitry Andric       break;
5260b57cec5SDimitry Andric     default:
5275ffd83dbSDimitry Andric       lldbassert(false && "pointer size is not 4 nor 8");
5280b57cec5SDimitry Andric     }
5290b57cec5SDimitry Andric     StreamString idx_name;
5300b57cec5SDimitry Andric     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric     DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
5330b57cec5SDimitry Andric                        process_sp->GetByteOrder(),
5340b57cec5SDimitry Andric                        process_sp->GetAddressByteSize());
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric     set_item.valobj_sp = CreateValueObjectFromData(
5370b57cec5SDimitry Andric         idx_name.GetString(), data, m_exe_ctx_ref,
5380b57cec5SDimitry Andric         m_backend.GetCompilerType().GetBasicTypeFromAST(
5390b57cec5SDimitry Andric             lldb::eBasicTypeObjCID));
5400b57cec5SDimitry Andric   }
5410b57cec5SDimitry Andric   return set_item.valobj_sp;
5420b57cec5SDimitry Andric }
5430b57cec5SDimitry Andric 
5445ffd83dbSDimitry Andric lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(
5455ffd83dbSDimitry Andric     lldb::ValueObjectSP valobj_sp)
54681ad6265SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),
54781ad6265SDimitry Andric       m_pair_type() {}
5485ffd83dbSDimitry Andric 
5495ffd83dbSDimitry Andric size_t
5505ffd83dbSDimitry Andric lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName(
5515ffd83dbSDimitry Andric     ConstString name) {
5525ffd83dbSDimitry Andric   const char *item_name = name.GetCString();
5535ffd83dbSDimitry Andric   const uint32_t idx = ExtractIndexFromString(item_name);
554*0fca6ea1SDimitry Andric   if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
5555ffd83dbSDimitry Andric     return UINT32_MAX;
5565ffd83dbSDimitry Andric   return idx;
5575ffd83dbSDimitry Andric }
5585ffd83dbSDimitry Andric 
559*0fca6ea1SDimitry Andric llvm::Expected<uint32_t>
5605ffd83dbSDimitry Andric lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {
5615ffd83dbSDimitry Andric   if (!m_hashtable.IsValid())
5625ffd83dbSDimitry Andric     return 0;
5635ffd83dbSDimitry Andric   return m_hashtable.GetCount();
5645ffd83dbSDimitry Andric }
5655ffd83dbSDimitry Andric 
566*0fca6ea1SDimitry Andric lldb::ChildCacheState
567*0fca6ea1SDimitry Andric lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() {
5685ffd83dbSDimitry Andric   m_children.clear();
5695ffd83dbSDimitry Andric   ValueObjectSP valobj_sp = m_backend.GetSP();
5705ffd83dbSDimitry Andric   m_ptr_size = 0;
5715ffd83dbSDimitry Andric   if (!valobj_sp)
572*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
5735ffd83dbSDimitry Andric   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
5745ffd83dbSDimitry Andric 
5755ffd83dbSDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
5765ffd83dbSDimitry Andric   if (!process_sp)
577*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
5785ffd83dbSDimitry Andric   m_ptr_size = process_sp->GetAddressByteSize();
5795ffd83dbSDimitry Andric   m_order = process_sp->GetByteOrder();
580*0fca6ea1SDimitry Andric   return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)
581*0fca6ea1SDimitry Andric              ? lldb::ChildCacheState::eReuse
582*0fca6ea1SDimitry Andric              : lldb::ChildCacheState::eRefetch;
5835ffd83dbSDimitry Andric }
5845ffd83dbSDimitry Andric 
5855ffd83dbSDimitry Andric bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() {
5865ffd83dbSDimitry Andric   return true;
5875ffd83dbSDimitry Andric }
5885ffd83dbSDimitry Andric 
5895ffd83dbSDimitry Andric lldb::ValueObjectSP
5905ffd83dbSDimitry Andric lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(
591*0fca6ea1SDimitry Andric     uint32_t idx) {
5925ffd83dbSDimitry Andric   lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
5935ffd83dbSDimitry Andric 
594*0fca6ea1SDimitry Andric   const uint32_t num_children = CalculateNumChildrenIgnoringErrors();
5955ffd83dbSDimitry Andric 
5965ffd83dbSDimitry Andric   if (idx >= num_children)
5975ffd83dbSDimitry Andric     return lldb::ValueObjectSP();
5985ffd83dbSDimitry Andric 
5995ffd83dbSDimitry Andric   if (m_children.empty()) {
6005ffd83dbSDimitry Andric     ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
6015ffd83dbSDimitry Andric     if (!process_sp)
6025ffd83dbSDimitry Andric       return lldb::ValueObjectSP();
6035ffd83dbSDimitry Andric 
6045ffd83dbSDimitry Andric     Status error;
6055ffd83dbSDimitry Andric     lldb::addr_t val_at_idx = 0;
6065ffd83dbSDimitry Andric 
6075ffd83dbSDimitry Andric     uint32_t tries = 0;
6085ffd83dbSDimitry Andric     uint32_t test_idx = 0;
6095ffd83dbSDimitry Andric 
6105ffd83dbSDimitry Andric     // Iterate over inferior memory, reading value pointers by shifting the
6115ffd83dbSDimitry Andric     // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
6125ffd83dbSDimitry Andric     // fails, otherwise, continue until the number of tries matches the number
6135ffd83dbSDimitry Andric     // of childen.
6145ffd83dbSDimitry Andric     while (tries < num_children) {
6155ffd83dbSDimitry Andric       val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
6165ffd83dbSDimitry Andric 
6175ffd83dbSDimitry Andric       val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
6185ffd83dbSDimitry Andric       if (error.Fail())
6195ffd83dbSDimitry Andric         return lldb::ValueObjectSP();
6205ffd83dbSDimitry Andric 
6215ffd83dbSDimitry Andric       test_idx++;
6225ffd83dbSDimitry Andric 
6235ffd83dbSDimitry Andric       if (!val_at_idx)
6245ffd83dbSDimitry Andric         continue;
6255ffd83dbSDimitry Andric       tries++;
6265ffd83dbSDimitry Andric 
6275ffd83dbSDimitry Andric       SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()};
6285ffd83dbSDimitry Andric 
6295ffd83dbSDimitry Andric       m_children.push_back(descriptor);
6305ffd83dbSDimitry Andric     }
6315ffd83dbSDimitry Andric   }
6325ffd83dbSDimitry Andric 
6335ffd83dbSDimitry Andric   if (idx >= m_children.size()) // should never happen
6345ffd83dbSDimitry Andric     return lldb::ValueObjectSP();
6355ffd83dbSDimitry Andric 
6365ffd83dbSDimitry Andric   SetItemDescriptor &set_item = m_children[idx];
6375ffd83dbSDimitry Andric   if (!set_item.valobj_sp) {
6385ffd83dbSDimitry Andric 
63981ad6265SDimitry Andric     WritableDataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0));
6405ffd83dbSDimitry Andric 
6415ffd83dbSDimitry Andric     switch (m_ptr_size) {
6425ffd83dbSDimitry Andric     case 0: // architecture has no clue - fail
6435ffd83dbSDimitry Andric       return lldb::ValueObjectSP();
6445ffd83dbSDimitry Andric     case 4:
6455ffd83dbSDimitry Andric       *reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) =
6465ffd83dbSDimitry Andric           static_cast<uint32_t>(set_item.item_ptr);
6475ffd83dbSDimitry Andric       break;
6485ffd83dbSDimitry Andric     case 8:
6495ffd83dbSDimitry Andric       *reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) =
6505ffd83dbSDimitry Andric           static_cast<uint64_t>(set_item.item_ptr);
6515ffd83dbSDimitry Andric       break;
6525ffd83dbSDimitry Andric     default:
6535ffd83dbSDimitry Andric       lldbassert(false && "pointer size is not 4 nor 8");
6545ffd83dbSDimitry Andric     }
6555ffd83dbSDimitry Andric     StreamString idx_name;
6565ffd83dbSDimitry Andric     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
6575ffd83dbSDimitry Andric 
6585ffd83dbSDimitry Andric     DataExtractor data(buffer_sp, m_order, m_ptr_size);
6595ffd83dbSDimitry Andric 
6605ffd83dbSDimitry Andric     set_item.valobj_sp = CreateValueObjectFromData(
6615ffd83dbSDimitry Andric         idx_name.GetString(), data, m_exe_ctx_ref,
6625ffd83dbSDimitry Andric         m_backend.GetCompilerType().GetBasicTypeFromAST(
6635ffd83dbSDimitry Andric             lldb::eBasicTypeObjCID));
6645ffd83dbSDimitry Andric   }
6655ffd83dbSDimitry Andric 
6665ffd83dbSDimitry Andric   return set_item.valobj_sp;
6675ffd83dbSDimitry Andric }
6685ffd83dbSDimitry Andric 
6690b57cec5SDimitry Andric template <typename D32, typename D64>
67081ad6265SDimitry Andric lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<
67181ad6265SDimitry Andric     D32, D64>::GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
67281ad6265SDimitry Andric     : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
6730b57cec5SDimitry Andric       m_data_32(nullptr), m_data_64(nullptr) {
6740b57cec5SDimitry Andric   if (valobj_sp)
6750b57cec5SDimitry Andric     Update();
6760b57cec5SDimitry Andric }
6770b57cec5SDimitry Andric 
6780b57cec5SDimitry Andric template <typename D32, typename D64>
679*0fca6ea1SDimitry Andric lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::
680*0fca6ea1SDimitry Andric     GenericNSSetMSyntheticFrontEnd::~GenericNSSetMSyntheticFrontEnd() {
6810b57cec5SDimitry Andric   delete m_data_32;
6820b57cec5SDimitry Andric   m_data_32 = nullptr;
6830b57cec5SDimitry Andric   delete m_data_64;
6840b57cec5SDimitry Andric   m_data_64 = nullptr;
6850b57cec5SDimitry Andric }
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric template <typename D32, typename D64>
6880b57cec5SDimitry Andric size_t
6890b57cec5SDimitry Andric lldb_private::formatters::
6900b57cec5SDimitry Andric   GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName(
6910b57cec5SDimitry Andric     ConstString name) {
6920b57cec5SDimitry Andric   const char *item_name = name.GetCString();
6930b57cec5SDimitry Andric   uint32_t idx = ExtractIndexFromString(item_name);
694*0fca6ea1SDimitry Andric   if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
6950b57cec5SDimitry Andric     return UINT32_MAX;
6960b57cec5SDimitry Andric   return idx;
6970b57cec5SDimitry Andric }
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric template <typename D32, typename D64>
700*0fca6ea1SDimitry Andric llvm::Expected<uint32_t>
701*0fca6ea1SDimitry Andric lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<
702*0fca6ea1SDimitry Andric     D32, D64>::CalculateNumChildren() {
7030b57cec5SDimitry Andric   if (!m_data_32 && !m_data_64)
7040b57cec5SDimitry Andric     return 0;
705*0fca6ea1SDimitry Andric   return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);
7060b57cec5SDimitry Andric }
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric template <typename D32, typename D64>
709*0fca6ea1SDimitry Andric lldb::ChildCacheState
710*0fca6ea1SDimitry Andric lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {
7110b57cec5SDimitry Andric   m_children.clear();
7120b57cec5SDimitry Andric   ValueObjectSP valobj_sp = m_backend.GetSP();
7130b57cec5SDimitry Andric   m_ptr_size = 0;
7140b57cec5SDimitry Andric   delete m_data_32;
7150b57cec5SDimitry Andric   m_data_32 = nullptr;
7160b57cec5SDimitry Andric   delete m_data_64;
7170b57cec5SDimitry Andric   m_data_64 = nullptr;
7180b57cec5SDimitry Andric   if (!valobj_sp)
719*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
7200b57cec5SDimitry Andric   if (!valobj_sp)
721*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
7220b57cec5SDimitry Andric   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
7230b57cec5SDimitry Andric   lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
7240b57cec5SDimitry Andric   if (!process_sp)
725*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
7260b57cec5SDimitry Andric   m_ptr_size = process_sp->GetAddressByteSize();
727fe6060f1SDimitry Andric   uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
728fe6060f1SDimitry Andric   Status error;
7290b57cec5SDimitry Andric   if (m_ptr_size == 4) {
7300b57cec5SDimitry Andric     m_data_32 = new D32();
7310b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
7320b57cec5SDimitry Andric                            error);
7330b57cec5SDimitry Andric   } else {
7340b57cec5SDimitry Andric     m_data_64 = new D64();
7350b57cec5SDimitry Andric     process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
7360b57cec5SDimitry Andric                            error);
7370b57cec5SDimitry Andric   }
738*0fca6ea1SDimitry Andric   return error.Success() ? lldb::ChildCacheState::eReuse
739*0fca6ea1SDimitry Andric                          : lldb::ChildCacheState::eRefetch;
7400b57cec5SDimitry Andric }
7410b57cec5SDimitry Andric 
7420b57cec5SDimitry Andric template <typename D32, typename D64>
7430b57cec5SDimitry Andric bool
7440b57cec5SDimitry Andric lldb_private::formatters::
7450b57cec5SDimitry Andric   GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() {
7460b57cec5SDimitry Andric   return true;
7470b57cec5SDimitry Andric }
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric template <typename D32, typename D64>
7500b57cec5SDimitry Andric lldb::ValueObjectSP
7510b57cec5SDimitry Andric lldb_private::formatters::
752*0fca6ea1SDimitry Andric   GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(uint32_t idx) {
7530b57cec5SDimitry Andric   lldb::addr_t m_objs_addr =
7540b57cec5SDimitry Andric       (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
7550b57cec5SDimitry Andric 
756*0fca6ea1SDimitry Andric   uint32_t num_children = CalculateNumChildrenIgnoringErrors();
7570b57cec5SDimitry Andric 
7580b57cec5SDimitry Andric   if (idx >= num_children)
7590b57cec5SDimitry Andric     return lldb::ValueObjectSP();
7600b57cec5SDimitry Andric 
7610b57cec5SDimitry Andric   ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
7620b57cec5SDimitry Andric   if (!process_sp)
7630b57cec5SDimitry Andric     return lldb::ValueObjectSP();
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric   if (m_children.empty()) {
7660b57cec5SDimitry Andric     // do the scan phase
7670b57cec5SDimitry Andric     lldb::addr_t obj_at_idx = 0;
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric     uint32_t tries = 0;
7700b57cec5SDimitry Andric     uint32_t test_idx = 0;
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric     while (tries < num_children) {
7730b57cec5SDimitry Andric       obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
7740b57cec5SDimitry Andric       if (!process_sp)
7750b57cec5SDimitry Andric         return lldb::ValueObjectSP();
7760b57cec5SDimitry Andric       Status error;
7770b57cec5SDimitry Andric       obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
7780b57cec5SDimitry Andric       if (error.Fail())
7790b57cec5SDimitry Andric         return lldb::ValueObjectSP();
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric       test_idx++;
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric       if (!obj_at_idx)
7840b57cec5SDimitry Andric         continue;
7850b57cec5SDimitry Andric       tries++;
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric       SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric       m_children.push_back(descriptor);
7900b57cec5SDimitry Andric     }
7910b57cec5SDimitry Andric   }
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric   if (idx >= m_children.size()) // should never happen
7940b57cec5SDimitry Andric     return lldb::ValueObjectSP();
7950b57cec5SDimitry Andric 
7960b57cec5SDimitry Andric   SetItemDescriptor &set_item = m_children[idx];
7970b57cec5SDimitry Andric   if (!set_item.valobj_sp) {
7980b57cec5SDimitry Andric     auto ptr_size = process_sp->GetAddressByteSize();
7990b57cec5SDimitry Andric     DataBufferHeap buffer(ptr_size, 0);
8000b57cec5SDimitry Andric     switch (ptr_size) {
8010b57cec5SDimitry Andric     case 0: // architecture has no clue?? - fail
8020b57cec5SDimitry Andric       return lldb::ValueObjectSP();
8030b57cec5SDimitry Andric     case 4:
8040b57cec5SDimitry Andric       *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
8050b57cec5SDimitry Andric       break;
8060b57cec5SDimitry Andric     case 8:
8070b57cec5SDimitry Andric       *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
8080b57cec5SDimitry Andric       break;
8090b57cec5SDimitry Andric     default:
8100b57cec5SDimitry Andric       assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
8110b57cec5SDimitry Andric     }
8120b57cec5SDimitry Andric     StreamString idx_name;
8130b57cec5SDimitry Andric     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
8140b57cec5SDimitry Andric 
8150b57cec5SDimitry Andric     DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
8160b57cec5SDimitry Andric                        process_sp->GetByteOrder(),
8170b57cec5SDimitry Andric                        process_sp->GetAddressByteSize());
8180b57cec5SDimitry Andric 
8190b57cec5SDimitry Andric     set_item.valobj_sp = CreateValueObjectFromData(
8200b57cec5SDimitry Andric         idx_name.GetString(), data, m_exe_ctx_ref,
8210b57cec5SDimitry Andric         m_backend.GetCompilerType().GetBasicTypeFromAST(
8220b57cec5SDimitry Andric             lldb::eBasicTypeObjCID));
8230b57cec5SDimitry Andric   }
8240b57cec5SDimitry Andric   return set_item.valobj_sp;
8250b57cec5SDimitry Andric }
8260b57cec5SDimitry Andric 
8270b57cec5SDimitry Andric template bool lldb_private::formatters::NSSetSummaryProvider<true>(
8280b57cec5SDimitry Andric     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric template bool lldb_private::formatters::NSSetSummaryProvider<false>(
8310b57cec5SDimitry Andric     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
832