brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.2 KiB · 150b233 Raw
805 lines · cpp
1//===-- NSSet.cpp ---------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "NSSet.h"10#include "CFBasicHash.h"11 12#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"13#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"14#include "lldb/DataFormatters/FormattersHelpers.h"15#include "lldb/Target/Language.h"16#include "lldb/Target/Target.h"17#include "lldb/Utility/DataBufferHeap.h"18#include "lldb/Utility/Endian.h"19#include "lldb/Utility/Status.h"20#include "lldb/Utility/Stream.h"21#include "lldb/ValueObject/ValueObject.h"22#include "lldb/ValueObject/ValueObjectConstResult.h"23 24using namespace lldb;25using namespace lldb_private;26using namespace lldb_private::formatters;27 28std::map<ConstString, CXXFunctionSummaryFormat::Callback> &29NSSet_Additionals::GetAdditionalSummaries() {30  static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;31  return g_map;32}33 34std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &35NSSet_Additionals::GetAdditionalSynthetics() {36  static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>37      g_map;38  return g_map;39}40 41namespace lldb_private {42namespace formatters {43class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {44public:45  NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);46 47  ~NSSetISyntheticFrontEnd() override;48 49  llvm::Expected<uint32_t> CalculateNumChildren() override;50 51  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;52 53  lldb::ChildCacheState Update() override;54 55  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;56 57private:58  struct DataDescriptor_32 {59    uint32_t _used : 26;60    uint32_t _szidx : 6;61  };62 63  struct DataDescriptor_64 {64    uint64_t _used : 58;65    uint32_t _szidx : 6;66  };67 68  struct SetItemDescriptor {69    lldb::addr_t item_ptr;70    lldb::ValueObjectSP valobj_sp;71  };72 73  ExecutionContextRef m_exe_ctx_ref;74  uint8_t m_ptr_size = 8;75  DataDescriptor_32 *m_data_32 = nullptr;76  DataDescriptor_64 *m_data_64 = nullptr;77  lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;78  std::vector<SetItemDescriptor> m_children;79};80 81class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd {82public:83  NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);84 85  llvm::Expected<uint32_t> CalculateNumChildren() override;86 87  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;88 89  lldb::ChildCacheState Update() override;90 91  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;92 93private:94  struct SetItemDescriptor {95    lldb::addr_t item_ptr;96    lldb::ValueObjectSP valobj_sp;97  };98 99  ExecutionContextRef m_exe_ctx_ref;100  uint8_t m_ptr_size = 8;101  lldb::ByteOrder m_order = lldb::eByteOrderInvalid;102 103  CFBasicHash m_hashtable;104 105  CompilerType m_pair_type;106  std::vector<SetItemDescriptor> m_children;107};108 109template <typename D32, typename D64>110class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {111public:112  GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);113 114  ~GenericNSSetMSyntheticFrontEnd() override;115 116  llvm::Expected<uint32_t> CalculateNumChildren() override;117 118  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;119 120  lldb::ChildCacheState Update() override;121 122  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;123 124private:125 126  struct SetItemDescriptor {127    lldb::addr_t item_ptr;128    lldb::ValueObjectSP valobj_sp;129  };130 131  ExecutionContextRef m_exe_ctx_ref;132  uint8_t m_ptr_size = 8;133  D32 *m_data_32;134  D64 *m_data_64;135  std::vector<SetItemDescriptor> m_children;136};137  138namespace Foundation1300 {139  struct DataDescriptor_32 {140    uint32_t _used : 26;141    uint32_t _size;142    uint32_t _mutations;143    uint32_t _objs_addr;144  };145  146  struct DataDescriptor_64 {147    uint64_t _used : 58;148    uint64_t _size;149    uint64_t _mutations;150    uint64_t _objs_addr;151  };152  153  using NSSetMSyntheticFrontEnd =154      GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;155}156  157namespace Foundation1428 {158  struct DataDescriptor_32 {159    uint32_t _used : 26;160    uint32_t _size;161    uint32_t _objs_addr;162    uint32_t _mutations;163  };164  165  struct DataDescriptor_64 {166    uint64_t _used : 58;167    uint64_t _size;168    uint64_t _objs_addr;169    uint64_t _mutations;170  };171  172  using NSSetMSyntheticFrontEnd =173      GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;174}175  176namespace Foundation1437 {177  struct DataDescriptor_32 {178    uint32_t _cow;179    // __table storage180    uint32_t _objs_addr;181    uint32_t _muts;182    uint32_t _used : 26;183    uint32_t _szidx : 6;184  };185  186  struct DataDescriptor_64 {187    uint64_t _cow;188    // __Table storage189    uint64_t _objs_addr;190    uint32_t _muts;191    uint32_t _used : 26;192    uint32_t _szidx : 6;193  };194  195  using NSSetMSyntheticFrontEnd =196      GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;197  198  template <typename DD>199  uint64_t200  __NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr,201                    Status &error) {202    const lldb::addr_t start_of_descriptor =203        valobj_addr + process.GetAddressByteSize();204    DD descriptor = DD();205    process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),206                       error);207    if (error.Fail()) {208      return 0;209    }210    return descriptor._used;211  }212  213  uint64_t214  __NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,215               Status &error) {216    if (process.GetAddressByteSize() == 4) {217      return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error);218    } else {219      return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error);220    }221  }222  } // namespace Foundation1437223} // namespace formatters224} // namespace lldb_private225 226template <bool cf_style>227bool lldb_private::formatters::NSSetSummaryProvider(228    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {229  static constexpr llvm::StringLiteral g_TypeHint("NSSet");230 231  ProcessSP process_sp = valobj.GetProcessSP();232  if (!process_sp)233    return false;234 235  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);236 237  if (!runtime)238    return false;239 240  ObjCLanguageRuntime::ClassDescriptorSP descriptor(241      runtime->GetClassDescriptor(valobj));242 243  if (!descriptor || !descriptor->IsValid())244    return false;245 246  uint32_t ptr_size = process_sp->GetAddressByteSize();247  bool is_64bit = (ptr_size == 8);248 249  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);250 251  if (!valobj_addr)252    return false;253 254  uint64_t value = 0;255 256  ConstString class_name(descriptor->GetClassName());257 258  static const ConstString g_SetI("__NSSetI");259  static const ConstString g_OrderedSetI("__NSOrderedSetI");260  static const ConstString g_SetM("__NSSetM");261  static const ConstString g_SetCF("__NSCFSet");262  static const ConstString g_SetCFRef("CFSetRef");263 264  if (class_name.IsEmpty())265    return false;266 267  if (class_name == g_SetI || class_name == g_OrderedSetI) {268    Status error;269    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,270                                                      ptr_size, 0, error);271    if (error.Fail())272      return false;273    value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);274  } else if (class_name == g_SetM) {275    AppleObjCRuntime *apple_runtime =276        llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);277    Status error;278    if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {279      value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error);280    } else {281      value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,282                                                        ptr_size, 0, error);283      value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);284    }285    if (error.Fail())286      return false;287  } else if (class_name == g_SetCF || class_name == g_SetCFRef) {288    ExecutionContext exe_ctx(process_sp);289    CFBasicHash cfbh;290    if (!cfbh.Update(valobj_addr, exe_ctx))291      return false;292    value = cfbh.GetCount();293  } else {294    auto &map(NSSet_Additionals::GetAdditionalSummaries());295    auto iter = map.find(class_name), end = map.end();296    if (iter != end)297      return iter->second(valobj, stream, options);298    else299      return false;300  }301 302  llvm::StringRef prefix, suffix;303  if (Language *language = Language::FindPlugin(options.GetLanguage()))304    std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);305 306  stream << prefix;307  stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");308  stream << suffix;309  return true;310}311 312SyntheticChildrenFrontEnd *313lldb_private::formatters::NSSetSyntheticFrontEndCreator(314    CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {315  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());316  if (!process_sp)317    return nullptr;318  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);319  if (!runtime)320    return nullptr;321 322  CompilerType valobj_type(valobj_sp->GetCompilerType());323  Flags flags(valobj_type.GetTypeInfo());324 325  if (flags.IsClear(eTypeIsPointer)) {326    Status error;327    valobj_sp = valobj_sp->AddressOf(error);328    if (error.Fail() || !valobj_sp)329      return nullptr;330  }331 332  ObjCLanguageRuntime::ClassDescriptorSP descriptor(333      runtime->GetClassDescriptor(*valobj_sp));334 335  if (!descriptor || !descriptor->IsValid())336    return nullptr;337 338  ConstString class_name = descriptor->GetClassName();339 340  static const ConstString g_SetI("__NSSetI");341  static const ConstString g_OrderedSetI("__NSOrderedSetI");342  static const ConstString g_SetM("__NSSetM");343  static const ConstString g_SetCF("__NSCFSet");344  static const ConstString g_SetCFRef("CFSetRef");345 346  if (class_name.IsEmpty())347    return nullptr;348 349  if (class_name == g_SetI || class_name == g_OrderedSetI) {350    return (new NSSetISyntheticFrontEnd(valobj_sp));351  } else if (class_name == g_SetM) {352    AppleObjCRuntime *apple_runtime =353        llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);354    if (apple_runtime) {355      if (apple_runtime->GetFoundationVersion() >= 1437)356        return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp));357      else if (apple_runtime->GetFoundationVersion() >= 1428)358        return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp));359      else360        return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));361    } else {362      return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));363    }364  } else if (class_name == g_SetCF || class_name == g_SetCFRef) {365    return (new NSCFSetSyntheticFrontEnd(valobj_sp));366  } else {367    auto &map(NSSet_Additionals::GetAdditionalSynthetics());368    auto iter = map.find(class_name), end = map.end();369    if (iter != end)370      return iter->second(synth, valobj_sp);371    return nullptr;372  }373}374 375lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(376    lldb::ValueObjectSP valobj_sp)377    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref() {378  if (valobj_sp)379    Update();380}381 382lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {383  delete m_data_32;384  m_data_32 = nullptr;385  delete m_data_64;386  m_data_64 = nullptr;387}388 389llvm::Expected<size_t>390lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(391    ConstString name) {392  auto optional_idx = ExtractIndexFromString(name.AsCString());393  if (!optional_idx) {394    return llvm::createStringError("Type has no child named '%s'",395                                   name.AsCString());396  }397  uint32_t idx = *optional_idx;398  if (idx >= CalculateNumChildrenIgnoringErrors())399    return llvm::createStringError("Type has no child named '%s'",400                                   name.AsCString());401  return idx;402}403 404llvm::Expected<uint32_t>405lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {406  if (!m_data_32 && !m_data_64)407    return 0;408  return (m_data_32 ? m_data_32->_used : m_data_64->_used);409}410 411lldb::ChildCacheState412lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {413  m_children.clear();414  delete m_data_32;415  m_data_32 = nullptr;416  delete m_data_64;417  m_data_64 = nullptr;418  m_ptr_size = 0;419  ValueObjectSP valobj_sp = m_backend.GetSP();420  if (!valobj_sp)421    return lldb::ChildCacheState::eRefetch;422  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();423  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());424  if (!process_sp)425    return lldb::ChildCacheState::eRefetch;426  m_ptr_size = process_sp->GetAddressByteSize();427  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;428  Status error;429  if (m_ptr_size == 4) {430    m_data_32 = new DataDescriptor_32();431    process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),432                           error);433  } else {434    m_data_64 = new DataDescriptor_64();435    process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),436                           error);437  }438  if (error.Fail())439    return lldb::ChildCacheState::eRefetch;440  m_data_ptr = data_location + m_ptr_size;441  return lldb::ChildCacheState::eReuse;442}443 444lldb::ValueObjectSP445lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(446    uint32_t idx) {447  uint32_t num_children = CalculateNumChildrenIgnoringErrors();448 449  if (idx >= num_children)450    return lldb::ValueObjectSP();451 452  ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();453  if (!process_sp)454    return lldb::ValueObjectSP();455 456  if (m_children.empty()) {457    // do the scan phase458    lldb::addr_t obj_at_idx = 0;459 460    uint32_t tries = 0;461    uint32_t test_idx = 0;462 463    while (tries < num_children) {464      obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);465      if (!process_sp)466        return lldb::ValueObjectSP();467      Status error;468      obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);469      if (error.Fail())470        return lldb::ValueObjectSP();471 472      test_idx++;473 474      if (!obj_at_idx)475        continue;476      tries++;477 478      SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};479 480      m_children.push_back(descriptor);481    }482  }483 484  if (idx >= m_children.size()) // should never happen485    return lldb::ValueObjectSP();486 487  SetItemDescriptor &set_item = m_children[idx];488  if (!set_item.valobj_sp) {489    auto ptr_size = process_sp->GetAddressByteSize();490    DataBufferHeap buffer(ptr_size, 0);491    switch (ptr_size) {492    case 0: // architecture has no clue - fail493      return lldb::ValueObjectSP();494    case 4:495      *reinterpret_cast<uint32_t *>(buffer.GetBytes()) =496          static_cast<uint32_t>(set_item.item_ptr);497      break;498    case 8:499      *reinterpret_cast<uint64_t *>(buffer.GetBytes()) =500          static_cast<uint64_t>(set_item.item_ptr);501      break;502    default:503      lldbassert(false && "pointer size is not 4 nor 8");504    }505    StreamString idx_name;506    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);507 508    DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),509                       process_sp->GetByteOrder(),510                       process_sp->GetAddressByteSize());511 512    set_item.valobj_sp = CreateValueObjectFromData(513        idx_name.GetString(), data, m_exe_ctx_ref,514        m_backend.GetCompilerType().GetBasicTypeFromAST(515            lldb::eBasicTypeObjCID));516  }517  return set_item.valobj_sp;518}519 520lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(521    lldb::ValueObjectSP valobj_sp)522    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),523      m_pair_type() {}524 525llvm::Expected<size_t>526lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName(527    ConstString name) {528  auto optional_idx = ExtractIndexFromString(name.AsCString());529  if (!optional_idx) {530    return llvm::createStringError("Type has no child named '%s'",531                                   name.AsCString());532  }533  uint32_t idx = *optional_idx;534  if (idx >= CalculateNumChildrenIgnoringErrors())535    return llvm::createStringError("Type has no child named '%s'",536                                   name.AsCString());537  return idx;538}539 540llvm::Expected<uint32_t>541lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {542  if (!m_hashtable.IsValid())543    return 0;544  return m_hashtable.GetCount();545}546 547lldb::ChildCacheState548lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() {549  m_children.clear();550  ValueObjectSP valobj_sp = m_backend.GetSP();551  m_ptr_size = 0;552  if (!valobj_sp)553    return lldb::ChildCacheState::eRefetch;554  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();555 556  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());557  if (!process_sp)558    return lldb::ChildCacheState::eRefetch;559  m_ptr_size = process_sp->GetAddressByteSize();560  m_order = process_sp->GetByteOrder();561  return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)562             ? lldb::ChildCacheState::eReuse563             : lldb::ChildCacheState::eRefetch;564}565 566lldb::ValueObjectSP567lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(568    uint32_t idx) {569  lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();570 571  const uint32_t num_children = CalculateNumChildrenIgnoringErrors();572 573  if (idx >= num_children)574    return lldb::ValueObjectSP();575 576  if (m_children.empty()) {577    ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();578    if (!process_sp)579      return lldb::ValueObjectSP();580 581    Status error;582    lldb::addr_t val_at_idx = 0;583 584    uint32_t tries = 0;585    uint32_t test_idx = 0;586 587    // Iterate over inferior memory, reading value pointers by shifting the588    // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read589    // fails, otherwise, continue until the number of tries matches the number590    // of childen.591    while (tries < num_children) {592      val_at_idx = m_values_ptr + (test_idx * m_ptr_size);593 594      val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);595      if (error.Fail())596        return lldb::ValueObjectSP();597 598      test_idx++;599 600      if (!val_at_idx)601        continue;602      tries++;603 604      SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()};605 606      m_children.push_back(descriptor);607    }608  }609 610  if (idx >= m_children.size()) // should never happen611    return lldb::ValueObjectSP();612 613  SetItemDescriptor &set_item = m_children[idx];614  if (!set_item.valobj_sp) {615 616    WritableDataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0));617 618    switch (m_ptr_size) {619    case 0: // architecture has no clue - fail620      return lldb::ValueObjectSP();621    case 4:622      *reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) =623          static_cast<uint32_t>(set_item.item_ptr);624      break;625    case 8:626      *reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) =627          static_cast<uint64_t>(set_item.item_ptr);628      break;629    default:630      lldbassert(false && "pointer size is not 4 nor 8");631    }632    StreamString idx_name;633    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);634 635    DataExtractor data(buffer_sp, m_order, m_ptr_size);636 637    set_item.valobj_sp = CreateValueObjectFromData(638        idx_name.GetString(), data, m_exe_ctx_ref,639        m_backend.GetCompilerType().GetBasicTypeFromAST(640            lldb::eBasicTypeObjCID));641  }642 643  return set_item.valobj_sp;644}645 646template <typename D32, typename D64>647lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<648    D32, D64>::GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)649    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),650      m_data_32(nullptr), m_data_64(nullptr) {651  if (valobj_sp)652    Update();653}654 655template <typename D32, typename D64>656lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::657    GenericNSSetMSyntheticFrontEnd::~GenericNSSetMSyntheticFrontEnd() {658  delete m_data_32;659  m_data_32 = nullptr;660  delete m_data_64;661  m_data_64 = nullptr;662}663 664template <typename D32, typename D64>665llvm::Expected<size_t> lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<666    D32, D64>::GetIndexOfChildWithName(ConstString name) {667  auto optional_idx = ExtractIndexFromString(name.AsCString());668  if (!optional_idx) {669    return llvm::createStringError("Type has no child named '%s'",670                                   name.AsCString());671  }672  uint32_t idx = *optional_idx;673  if (idx >= CalculateNumChildrenIgnoringErrors())674    return llvm::createStringError("Type has no child named '%s'",675                                   name.AsCString());676  return idx;677}678 679template <typename D32, typename D64>680llvm::Expected<uint32_t>681lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<682    D32, D64>::CalculateNumChildren() {683  if (!m_data_32 && !m_data_64)684    return 0;685  return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);686}687 688template <typename D32, typename D64>689lldb::ChildCacheState690lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {691  m_children.clear();692  ValueObjectSP valobj_sp = m_backend.GetSP();693  m_ptr_size = 0;694  delete m_data_32;695  m_data_32 = nullptr;696  delete m_data_64;697  m_data_64 = nullptr;698  if (!valobj_sp)699    return lldb::ChildCacheState::eRefetch;700  if (!valobj_sp)701    return lldb::ChildCacheState::eRefetch;702  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();703  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());704  if (!process_sp)705    return lldb::ChildCacheState::eRefetch;706  m_ptr_size = process_sp->GetAddressByteSize();707  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;708  Status error;709  if (m_ptr_size == 4) {710    m_data_32 = new D32();711    process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),712                           error);713  } else {714    m_data_64 = new D64();715    process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),716                           error);717  }718  return error.Success() ? lldb::ChildCacheState::eReuse719                         : lldb::ChildCacheState::eRefetch;720}721 722template <typename D32, typename D64>723lldb::ValueObjectSP724lldb_private::formatters::725  GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(uint32_t idx) {726  lldb::addr_t m_objs_addr =727      (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);728 729  uint32_t num_children = CalculateNumChildrenIgnoringErrors();730 731  if (idx >= num_children)732    return lldb::ValueObjectSP();733 734  ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();735  if (!process_sp)736    return lldb::ValueObjectSP();737 738  if (m_children.empty()) {739    // do the scan phase740    lldb::addr_t obj_at_idx = 0;741 742    uint32_t tries = 0;743    uint32_t test_idx = 0;744 745    while (tries < num_children) {746      obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);747      if (!process_sp)748        return lldb::ValueObjectSP();749      Status error;750      obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);751      if (error.Fail())752        return lldb::ValueObjectSP();753 754      test_idx++;755 756      if (!obj_at_idx)757        continue;758      tries++;759 760      SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};761 762      m_children.push_back(descriptor);763    }764  }765 766  if (idx >= m_children.size()) // should never happen767    return lldb::ValueObjectSP();768 769  SetItemDescriptor &set_item = m_children[idx];770  if (!set_item.valobj_sp) {771    auto ptr_size = process_sp->GetAddressByteSize();772    DataBufferHeap buffer(ptr_size, 0);773    switch (ptr_size) {774    case 0: // architecture has no clue?? - fail775      return lldb::ValueObjectSP();776    case 4:777      *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;778      break;779    case 8:780      *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;781      break;782    default:783      assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");784    }785    StreamString idx_name;786    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);787 788    DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),789                       process_sp->GetByteOrder(),790                       process_sp->GetAddressByteSize());791 792    set_item.valobj_sp = CreateValueObjectFromData(793        idx_name.GetString(), data, m_exe_ctx_ref,794        m_backend.GetCompilerType().GetBasicTypeFromAST(795            lldb::eBasicTypeObjCID));796  }797  return set_item.valobj_sp;798}799 800template bool lldb_private::formatters::NSSetSummaryProvider<true>(801    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);802 803template bool lldb_private::formatters::NSSetSummaryProvider<false>(804    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);805