Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp
39644 views
//===-- NSSet.cpp ---------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "NSSet.h"9#include "CFBasicHash.h"1011#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"12#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"13#include "lldb/Core/ValueObject.h"14#include "lldb/Core/ValueObjectConstResult.h"15#include "lldb/DataFormatters/FormattersHelpers.h"16#include "lldb/Target/Language.h"17#include "lldb/Target/Target.h"18#include "lldb/Utility/DataBufferHeap.h"19#include "lldb/Utility/Endian.h"20#include "lldb/Utility/Status.h"21#include "lldb/Utility/Stream.h"2223using namespace lldb;24using namespace lldb_private;25using namespace lldb_private::formatters;2627std::map<ConstString, CXXFunctionSummaryFormat::Callback> &28NSSet_Additionals::GetAdditionalSummaries() {29static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;30return g_map;31}3233std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &34NSSet_Additionals::GetAdditionalSynthetics() {35static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>36g_map;37return g_map;38}3940namespace lldb_private {41namespace formatters {42class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {43public:44NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);4546~NSSetISyntheticFrontEnd() override;4748llvm::Expected<uint32_t> CalculateNumChildren() override;4950lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;5152lldb::ChildCacheState Update() override;5354bool MightHaveChildren() override;5556size_t GetIndexOfChildWithName(ConstString name) override;5758private:59struct DataDescriptor_32 {60uint32_t _used : 26;61uint32_t _szidx : 6;62};6364struct DataDescriptor_64 {65uint64_t _used : 58;66uint32_t _szidx : 6;67};6869struct SetItemDescriptor {70lldb::addr_t item_ptr;71lldb::ValueObjectSP valobj_sp;72};7374ExecutionContextRef m_exe_ctx_ref;75uint8_t m_ptr_size = 8;76DataDescriptor_32 *m_data_32 = nullptr;77DataDescriptor_64 *m_data_64 = nullptr;78lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;79std::vector<SetItemDescriptor> m_children;80};8182class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd {83public:84NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);8586llvm::Expected<uint32_t> CalculateNumChildren() override;8788lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;8990lldb::ChildCacheState Update() override;9192bool MightHaveChildren() override;9394size_t GetIndexOfChildWithName(ConstString name) override;9596private:97struct SetItemDescriptor {98lldb::addr_t item_ptr;99lldb::ValueObjectSP valobj_sp;100};101102ExecutionContextRef m_exe_ctx_ref;103uint8_t m_ptr_size = 8;104lldb::ByteOrder m_order = lldb::eByteOrderInvalid;105106CFBasicHash m_hashtable;107108CompilerType m_pair_type;109std::vector<SetItemDescriptor> m_children;110};111112template <typename D32, typename D64>113class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {114public:115GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);116117~GenericNSSetMSyntheticFrontEnd() override;118119llvm::Expected<uint32_t> CalculateNumChildren() override;120121lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;122123lldb::ChildCacheState Update() override;124125bool MightHaveChildren() override;126127size_t GetIndexOfChildWithName(ConstString name) override;128129private:130131struct SetItemDescriptor {132lldb::addr_t item_ptr;133lldb::ValueObjectSP valobj_sp;134};135136ExecutionContextRef m_exe_ctx_ref;137uint8_t m_ptr_size = 8;138D32 *m_data_32;139D64 *m_data_64;140std::vector<SetItemDescriptor> m_children;141};142143namespace Foundation1300 {144struct DataDescriptor_32 {145uint32_t _used : 26;146uint32_t _size;147uint32_t _mutations;148uint32_t _objs_addr;149};150151struct DataDescriptor_64 {152uint64_t _used : 58;153uint64_t _size;154uint64_t _mutations;155uint64_t _objs_addr;156};157158using NSSetMSyntheticFrontEnd =159GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;160}161162namespace Foundation1428 {163struct DataDescriptor_32 {164uint32_t _used : 26;165uint32_t _size;166uint32_t _objs_addr;167uint32_t _mutations;168};169170struct DataDescriptor_64 {171uint64_t _used : 58;172uint64_t _size;173uint64_t _objs_addr;174uint64_t _mutations;175};176177using NSSetMSyntheticFrontEnd =178GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;179}180181namespace Foundation1437 {182struct DataDescriptor_32 {183uint32_t _cow;184// __table storage185uint32_t _objs_addr;186uint32_t _muts;187uint32_t _used : 26;188uint32_t _szidx : 6;189};190191struct DataDescriptor_64 {192uint64_t _cow;193// __Table storage194uint64_t _objs_addr;195uint32_t _muts;196uint32_t _used : 26;197uint32_t _szidx : 6;198};199200using NSSetMSyntheticFrontEnd =201GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;202203template <typename DD>204uint64_t205__NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr,206Status &error) {207const lldb::addr_t start_of_descriptor =208valobj_addr + process.GetAddressByteSize();209DD descriptor = DD();210process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),211error);212if (error.Fail()) {213return 0;214}215return descriptor._used;216}217218uint64_t219__NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,220Status &error) {221if (process.GetAddressByteSize() == 4) {222return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error);223} else {224return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error);225}226}227}228229class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {230public:231NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);232233~NSSetCodeRunningSyntheticFrontEnd() override;234235llvm::Expected<uint32_t> CalculateNumChildren() override;236237lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;238239lldb::ChildCacheState Update() override;240241bool MightHaveChildren() override;242243size_t GetIndexOfChildWithName(ConstString name) override;244};245} // namespace formatters246} // namespace lldb_private247248template <bool cf_style>249bool lldb_private::formatters::NSSetSummaryProvider(250ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {251static constexpr llvm::StringLiteral g_TypeHint("NSSet");252253ProcessSP process_sp = valobj.GetProcessSP();254if (!process_sp)255return false;256257ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);258259if (!runtime)260return false;261262ObjCLanguageRuntime::ClassDescriptorSP descriptor(263runtime->GetClassDescriptor(valobj));264265if (!descriptor || !descriptor->IsValid())266return false;267268uint32_t ptr_size = process_sp->GetAddressByteSize();269bool is_64bit = (ptr_size == 8);270271lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);272273if (!valobj_addr)274return false;275276uint64_t value = 0;277278ConstString class_name(descriptor->GetClassName());279280static const ConstString g_SetI("__NSSetI");281static const ConstString g_OrderedSetI("__NSOrderedSetI");282static const ConstString g_SetM("__NSSetM");283static const ConstString g_SetCF("__NSCFSet");284static const ConstString g_SetCFRef("CFSetRef");285286if (class_name.IsEmpty())287return false;288289if (class_name == g_SetI || class_name == g_OrderedSetI) {290Status error;291value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,292ptr_size, 0, error);293if (error.Fail())294return false;295value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);296} else if (class_name == g_SetM) {297AppleObjCRuntime *apple_runtime =298llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);299Status error;300if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {301value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error);302} else {303value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,304ptr_size, 0, error);305value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);306}307if (error.Fail())308return false;309} else if (class_name == g_SetCF || class_name == g_SetCFRef) {310ExecutionContext exe_ctx(process_sp);311CFBasicHash cfbh;312if (!cfbh.Update(valobj_addr, exe_ctx))313return false;314value = cfbh.GetCount();315} else {316auto &map(NSSet_Additionals::GetAdditionalSummaries());317auto iter = map.find(class_name), end = map.end();318if (iter != end)319return iter->second(valobj, stream, options);320else321return false;322}323324llvm::StringRef prefix, suffix;325if (Language *language = Language::FindPlugin(options.GetLanguage()))326std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);327328stream << prefix;329stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");330stream << suffix;331return true;332}333334SyntheticChildrenFrontEnd *335lldb_private::formatters::NSSetSyntheticFrontEndCreator(336CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {337lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());338if (!process_sp)339return nullptr;340ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);341if (!runtime)342return nullptr;343344CompilerType valobj_type(valobj_sp->GetCompilerType());345Flags flags(valobj_type.GetTypeInfo());346347if (flags.IsClear(eTypeIsPointer)) {348Status error;349valobj_sp = valobj_sp->AddressOf(error);350if (error.Fail() || !valobj_sp)351return nullptr;352}353354ObjCLanguageRuntime::ClassDescriptorSP descriptor(355runtime->GetClassDescriptor(*valobj_sp));356357if (!descriptor || !descriptor->IsValid())358return nullptr;359360ConstString class_name = descriptor->GetClassName();361362static const ConstString g_SetI("__NSSetI");363static const ConstString g_OrderedSetI("__NSOrderedSetI");364static const ConstString g_SetM("__NSSetM");365static const ConstString g_SetCF("__NSCFSet");366static const ConstString g_SetCFRef("CFSetRef");367368if (class_name.IsEmpty())369return nullptr;370371if (class_name == g_SetI || class_name == g_OrderedSetI) {372return (new NSSetISyntheticFrontEnd(valobj_sp));373} else if (class_name == g_SetM) {374AppleObjCRuntime *apple_runtime =375llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);376if (apple_runtime) {377if (apple_runtime->GetFoundationVersion() >= 1437)378return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp));379else if (apple_runtime->GetFoundationVersion() >= 1428)380return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp));381else382return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));383} else {384return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));385}386} else if (class_name == g_SetCF || class_name == g_SetCFRef) {387return (new NSCFSetSyntheticFrontEnd(valobj_sp));388} else {389auto &map(NSSet_Additionals::GetAdditionalSynthetics());390auto iter = map.find(class_name), end = map.end();391if (iter != end)392return iter->second(synth, valobj_sp);393return nullptr;394}395}396397lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(398lldb::ValueObjectSP valobj_sp)399: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref() {400if (valobj_sp)401Update();402}403404lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {405delete m_data_32;406m_data_32 = nullptr;407delete m_data_64;408m_data_64 = nullptr;409}410411size_t412lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(413ConstString name) {414const char *item_name = name.GetCString();415uint32_t idx = ExtractIndexFromString(item_name);416if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())417return UINT32_MAX;418return idx;419}420421llvm::Expected<uint32_t>422lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {423if (!m_data_32 && !m_data_64)424return 0;425return (m_data_32 ? m_data_32->_used : m_data_64->_used);426}427428lldb::ChildCacheState429lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {430m_children.clear();431delete m_data_32;432m_data_32 = nullptr;433delete m_data_64;434m_data_64 = nullptr;435m_ptr_size = 0;436ValueObjectSP valobj_sp = m_backend.GetSP();437if (!valobj_sp)438return lldb::ChildCacheState::eRefetch;439if (!valobj_sp)440return lldb::ChildCacheState::eRefetch;441m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();442lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());443if (!process_sp)444return lldb::ChildCacheState::eRefetch;445m_ptr_size = process_sp->GetAddressByteSize();446uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;447Status error;448if (m_ptr_size == 4) {449m_data_32 = new DataDescriptor_32();450process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),451error);452} else {453m_data_64 = new DataDescriptor_64();454process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),455error);456}457if (error.Fail())458return lldb::ChildCacheState::eRefetch;459m_data_ptr = data_location + m_ptr_size;460return lldb::ChildCacheState::eReuse;461}462463bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() {464return true;465}466467lldb::ValueObjectSP468lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(469uint32_t idx) {470uint32_t num_children = CalculateNumChildrenIgnoringErrors();471472if (idx >= num_children)473return lldb::ValueObjectSP();474475ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();476if (!process_sp)477return lldb::ValueObjectSP();478479if (m_children.empty()) {480// do the scan phase481lldb::addr_t obj_at_idx = 0;482483uint32_t tries = 0;484uint32_t test_idx = 0;485486while (tries < num_children) {487obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);488if (!process_sp)489return lldb::ValueObjectSP();490Status error;491obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);492if (error.Fail())493return lldb::ValueObjectSP();494495test_idx++;496497if (!obj_at_idx)498continue;499tries++;500501SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};502503m_children.push_back(descriptor);504}505}506507if (idx >= m_children.size()) // should never happen508return lldb::ValueObjectSP();509510SetItemDescriptor &set_item = m_children[idx];511if (!set_item.valobj_sp) {512auto ptr_size = process_sp->GetAddressByteSize();513DataBufferHeap buffer(ptr_size, 0);514switch (ptr_size) {515case 0: // architecture has no clue - fail516return lldb::ValueObjectSP();517case 4:518*reinterpret_cast<uint32_t *>(buffer.GetBytes()) =519static_cast<uint32_t>(set_item.item_ptr);520break;521case 8:522*reinterpret_cast<uint64_t *>(buffer.GetBytes()) =523static_cast<uint64_t>(set_item.item_ptr);524break;525default:526lldbassert(false && "pointer size is not 4 nor 8");527}528StreamString idx_name;529idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);530531DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),532process_sp->GetByteOrder(),533process_sp->GetAddressByteSize());534535set_item.valobj_sp = CreateValueObjectFromData(536idx_name.GetString(), data, m_exe_ctx_ref,537m_backend.GetCompilerType().GetBasicTypeFromAST(538lldb::eBasicTypeObjCID));539}540return set_item.valobj_sp;541}542543lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(544lldb::ValueObjectSP valobj_sp)545: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),546m_pair_type() {}547548size_t549lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName(550ConstString name) {551const char *item_name = name.GetCString();552const uint32_t idx = ExtractIndexFromString(item_name);553if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())554return UINT32_MAX;555return idx;556}557558llvm::Expected<uint32_t>559lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {560if (!m_hashtable.IsValid())561return 0;562return m_hashtable.GetCount();563}564565lldb::ChildCacheState566lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() {567m_children.clear();568ValueObjectSP valobj_sp = m_backend.GetSP();569m_ptr_size = 0;570if (!valobj_sp)571return lldb::ChildCacheState::eRefetch;572m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();573574lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());575if (!process_sp)576return lldb::ChildCacheState::eRefetch;577m_ptr_size = process_sp->GetAddressByteSize();578m_order = process_sp->GetByteOrder();579return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)580? lldb::ChildCacheState::eReuse581: lldb::ChildCacheState::eRefetch;582}583584bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() {585return true;586}587588lldb::ValueObjectSP589lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(590uint32_t idx) {591lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();592593const uint32_t num_children = CalculateNumChildrenIgnoringErrors();594595if (idx >= num_children)596return lldb::ValueObjectSP();597598if (m_children.empty()) {599ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();600if (!process_sp)601return lldb::ValueObjectSP();602603Status error;604lldb::addr_t val_at_idx = 0;605606uint32_t tries = 0;607uint32_t test_idx = 0;608609// Iterate over inferior memory, reading value pointers by shifting the610// cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read611// fails, otherwise, continue until the number of tries matches the number612// of childen.613while (tries < num_children) {614val_at_idx = m_values_ptr + (test_idx * m_ptr_size);615616val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);617if (error.Fail())618return lldb::ValueObjectSP();619620test_idx++;621622if (!val_at_idx)623continue;624tries++;625626SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()};627628m_children.push_back(descriptor);629}630}631632if (idx >= m_children.size()) // should never happen633return lldb::ValueObjectSP();634635SetItemDescriptor &set_item = m_children[idx];636if (!set_item.valobj_sp) {637638WritableDataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0));639640switch (m_ptr_size) {641case 0: // architecture has no clue - fail642return lldb::ValueObjectSP();643case 4:644*reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) =645static_cast<uint32_t>(set_item.item_ptr);646break;647case 8:648*reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) =649static_cast<uint64_t>(set_item.item_ptr);650break;651default:652lldbassert(false && "pointer size is not 4 nor 8");653}654StreamString idx_name;655idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);656657DataExtractor data(buffer_sp, m_order, m_ptr_size);658659set_item.valobj_sp = CreateValueObjectFromData(660idx_name.GetString(), data, m_exe_ctx_ref,661m_backend.GetCompilerType().GetBasicTypeFromAST(662lldb::eBasicTypeObjCID));663}664665return set_item.valobj_sp;666}667668template <typename D32, typename D64>669lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<670D32, D64>::GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)671: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),672m_data_32(nullptr), m_data_64(nullptr) {673if (valobj_sp)674Update();675}676677template <typename D32, typename D64>678lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::679GenericNSSetMSyntheticFrontEnd::~GenericNSSetMSyntheticFrontEnd() {680delete m_data_32;681m_data_32 = nullptr;682delete m_data_64;683m_data_64 = nullptr;684}685686template <typename D32, typename D64>687size_t688lldb_private::formatters::689GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName(690ConstString name) {691const char *item_name = name.GetCString();692uint32_t idx = ExtractIndexFromString(item_name);693if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())694return UINT32_MAX;695return idx;696}697698template <typename D32, typename D64>699llvm::Expected<uint32_t>700lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<701D32, D64>::CalculateNumChildren() {702if (!m_data_32 && !m_data_64)703return 0;704return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);705}706707template <typename D32, typename D64>708lldb::ChildCacheState709lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {710m_children.clear();711ValueObjectSP valobj_sp = m_backend.GetSP();712m_ptr_size = 0;713delete m_data_32;714m_data_32 = nullptr;715delete m_data_64;716m_data_64 = nullptr;717if (!valobj_sp)718return lldb::ChildCacheState::eRefetch;719if (!valobj_sp)720return lldb::ChildCacheState::eRefetch;721m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();722lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());723if (!process_sp)724return lldb::ChildCacheState::eRefetch;725m_ptr_size = process_sp->GetAddressByteSize();726uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;727Status error;728if (m_ptr_size == 4) {729m_data_32 = new D32();730process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),731error);732} else {733m_data_64 = new D64();734process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),735error);736}737return error.Success() ? lldb::ChildCacheState::eReuse738: lldb::ChildCacheState::eRefetch;739}740741template <typename D32, typename D64>742bool743lldb_private::formatters::744GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() {745return true;746}747748template <typename D32, typename D64>749lldb::ValueObjectSP750lldb_private::formatters::751GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(uint32_t idx) {752lldb::addr_t m_objs_addr =753(m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);754755uint32_t num_children = CalculateNumChildrenIgnoringErrors();756757if (idx >= num_children)758return lldb::ValueObjectSP();759760ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();761if (!process_sp)762return lldb::ValueObjectSP();763764if (m_children.empty()) {765// do the scan phase766lldb::addr_t obj_at_idx = 0;767768uint32_t tries = 0;769uint32_t test_idx = 0;770771while (tries < num_children) {772obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);773if (!process_sp)774return lldb::ValueObjectSP();775Status error;776obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);777if (error.Fail())778return lldb::ValueObjectSP();779780test_idx++;781782if (!obj_at_idx)783continue;784tries++;785786SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};787788m_children.push_back(descriptor);789}790}791792if (idx >= m_children.size()) // should never happen793return lldb::ValueObjectSP();794795SetItemDescriptor &set_item = m_children[idx];796if (!set_item.valobj_sp) {797auto ptr_size = process_sp->GetAddressByteSize();798DataBufferHeap buffer(ptr_size, 0);799switch (ptr_size) {800case 0: // architecture has no clue?? - fail801return lldb::ValueObjectSP();802case 4:803*((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;804break;805case 8:806*((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;807break;808default:809assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");810}811StreamString idx_name;812idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);813814DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),815process_sp->GetByteOrder(),816process_sp->GetAddressByteSize());817818set_item.valobj_sp = CreateValueObjectFromData(819idx_name.GetString(), data, m_exe_ctx_ref,820m_backend.GetCompilerType().GetBasicTypeFromAST(821lldb::eBasicTypeObjCID));822}823return set_item.valobj_sp;824}825826template bool lldb_private::formatters::NSSetSummaryProvider<true>(827ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);828829template bool lldb_private::formatters::NSSetSummaryProvider<false>(830ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);831832833