118316Swollman//===-- NSSet.cpp -----------------------------------------------*- C++ -*-===//
218316Swollman//
318316Swollman// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
418316Swollman// See https://llvm.org/LICENSE.txt for license information.
518316Swollman// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618316Swollman//
718316Swollman//===----------------------------------------------------------------------===//
818316Swollman
918316Swollman#include "NSSet.h"
1018316Swollman
1118316Swollman#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
1218316Swollman#include "lldb/Core/ValueObject.h"
1318316Swollman#include "lldb/Core/ValueObjectConstResult.h"
1418316Swollman#include "lldb/DataFormatters/FormattersHelpers.h"
1518316Swollman#include "lldb/Symbol/ClangASTContext.h"
1618316Swollman#include "lldb/Target/Language.h"
1718316Swollman#include "lldb/Target/Target.h"
1818316Swollman#include "lldb/Utility/DataBufferHeap.h"
1918316Swollman#include "lldb/Utility/Endian.h"
2018316Swollman#include "lldb/Utility/Status.h"
2118316Swollman#include "lldb/Utility/Stream.h"
2218316Swollman
2318316Swollmanusing namespace lldb;
2418316Swollmanusing namespace lldb_private;
2518316Swollmanusing namespace lldb_private::formatters;
2618316Swollman
2718316Swollmanstd::map<ConstString, CXXFunctionSummaryFormat::Callback> &
2846303SmarkmNSSet_Additionals::GetAdditionalSummaries() {
2950476Speter  static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
3018316Swollman  return g_map;
3118316Swollman}
3218316Swollman
3318316Swollmanstd::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
3420339SwollmanNSSet_Additionals::GetAdditionalSynthetics() {
3518316Swollman  static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
36126250Sbms      g_map;
3746303Smarkm  return g_map;
38126250Sbms}
39126250Sbms
40126250Sbmsnamespace lldb_private {
41126250Sbmsnamespace formatters {
42126250Sbmsclass NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
4346303Smarkmpublic:
4446303Smarkm  NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
4546303Smarkm
46190715Sphk  ~NSSetISyntheticFrontEnd() override;
4718316Swollman
4846303Smarkm  size_t CalculateNumChildren() override;
4919880Swollman
5018316Swollman  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
5118316Swollman
5218316Swollman  bool Update() override;
5318316Swollman
5418316Swollman  bool MightHaveChildren() override;
5518316Swollman
5618316Swollman  size_t GetIndexOfChildWithName(ConstString name) override;
5746303Smarkm
5818316Swollmanprivate:
5920339Swollman  struct DataDescriptor_32 {
6018316Swollman    uint32_t _used : 26;
6118316Swollman    uint32_t _szidx : 6;
6218316Swollman  };
6318316Swollman
6419880Swollman  struct DataDescriptor_64 {
6519880Swollman    uint64_t _used : 58;
6619880Swollman    uint32_t _szidx : 6;
6719880Swollman  };
6819880Swollman
6919880Swollman  struct SetItemDescriptor {
7019880Swollman    lldb::addr_t item_ptr;
7118316Swollman    lldb::ValueObjectSP valobj_sp;
7218316Swollman  };
7318316Swollman
7420339Swollman  ExecutionContextRef m_exe_ctx_ref;
7520339Swollman  uint8_t m_ptr_size;
7620339Swollman  DataDescriptor_32 *m_data_32;
7720339Swollman  DataDescriptor_64 *m_data_64;
7846303Smarkm  lldb::addr_t m_data_ptr;
7946303Smarkm  std::vector<SetItemDescriptor> m_children;
8046303Smarkm};
8120339Swollman
8218316Swollmantemplate <typename D32, typename D64>
8318316Swollmanclass GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
8418316Swollmanpublic:
8518316Swollman  GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
86126250Sbms
87126250Sbms  ~GenericNSSetMSyntheticFrontEnd() override;
88126250Sbms
89126250Sbms  size_t CalculateNumChildren() override;
9019880Swollman
9118316Swollman  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
9219880Swollman
9319880Swollman  bool Update() override;
9419880Swollman
9519880Swollman  bool MightHaveChildren() override;
9619880Swollman
9719880Swollman  size_t GetIndexOfChildWithName(ConstString name) override;
9818316Swollman
9918316Swollmanprivate:
10018316Swollman
10119880Swollman  struct SetItemDescriptor {
10218316Swollman    lldb::addr_t item_ptr;
10318316Swollman    lldb::ValueObjectSP valobj_sp;
10418316Swollman  };
10518316Swollman
10618316Swollman  ExecutionContextRef m_exe_ctx_ref;
10719880Swollman  uint8_t m_ptr_size;
10818316Swollman  D32 *m_data_32;
10918316Swollman  D64 *m_data_64;
11018316Swollman  std::vector<SetItemDescriptor> m_children;
11118316Swollman};
11218316Swollman
11318316Swollmannamespace Foundation1300 {
11418316Swollman  struct DataDescriptor_32 {
11546303Smarkm    uint32_t _used : 26;
11618316Swollman    uint32_t _size;
11746303Smarkm    uint32_t _mutations;
11818316Swollman    uint32_t _objs_addr;
11918316Swollman  };
12018316Swollman
12118316Swollman  struct DataDescriptor_64 {
12218316Swollman    uint64_t _used : 58;
12318316Swollman    uint64_t _size;
12419880Swollman    uint64_t _mutations;
12519880Swollman    uint64_t _objs_addr;
12619880Swollman  };
12720339Swollman
12819880Swollman  using NSSetMSyntheticFrontEnd =
12919880Swollman      GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
13019880Swollman}
13119880Swollman
13219880Swollmannamespace Foundation1428 {
13319880Swollman  struct DataDescriptor_32 {
13419880Swollman    uint32_t _used : 26;
13519880Swollman    uint32_t _size;
13620339Swollman    uint32_t _objs_addr;
13720339Swollman    uint32_t _mutations;
13820339Swollman  };
13920339Swollman
14020339Swollman  struct DataDescriptor_64 {
14120339Swollman    uint64_t _used : 58;
14220339Swollman    uint64_t _size;
14320339Swollman    uint64_t _objs_addr;
14419880Swollman    uint64_t _mutations;
14518316Swollman  };
14618316Swollman
14718316Swollman  using NSSetMSyntheticFrontEnd =
14818316Swollman      GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
14918316Swollman}
15018316Swollman
15118316Swollmannamespace Foundation1437 {
15218316Swollman  struct DataDescriptor_32 {
15318316Swollman    uint32_t _cow;
15418316Swollman    // __table storage
15518316Swollman    uint32_t _objs_addr;
15618316Swollman    uint32_t _muts;
15718316Swollman    uint32_t _used : 26;
15818316Swollman    uint32_t _szidx : 6;
15918316Swollman  };
16018316Swollman
16118316Swollman  struct DataDescriptor_64 {
16218316Swollman    uint64_t _cow;
16318316Swollman    // __Table storage
16418316Swollman    uint64_t _objs_addr;
16518316Swollman    uint32_t _muts;
16618316Swollman    uint32_t _used : 26;
16718316Swollman    uint32_t _szidx : 6;
16818316Swollman  };
16946303Smarkm
17046303Smarkm  using NSSetMSyntheticFrontEnd =
17146303Smarkm      GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
17218316Swollman
17318316Swollman  template <typename DD>
17446303Smarkm  uint64_t
17520339Swollman  __NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr,
17618316Swollman                    Status &error) {
17746303Smarkm    const lldb::addr_t start_of_descriptor =
17818316Swollman        valobj_addr + process.GetAddressByteSize();
17918316Swollman    DD descriptor = DD();
18018316Swollman    process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
18118316Swollman                       error);
18218316Swollman    if (error.Fail()) {
18318316Swollman      return 0;
18420339Swollman    }
18520339Swollman    return descriptor._used;
18620339Swollman  }
18720339Swollman
18820339Swollman  uint64_t
18920339Swollman  __NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
19046303Smarkm               Status &error) {
191230045Skevlo    if (process.GetAddressByteSize() == 4) {
19218316Swollman      return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error);
19318316Swollman    } else {
19418316Swollman      return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error);
19518316Swollman    }
19646303Smarkm  }
19746303Smarkm}
19846303Smarkm
19946303Smarkmclass NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
20046303Smarkmpublic:
20118316Swollman  NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
20218316Swollman
20318316Swollman  ~NSSetCodeRunningSyntheticFrontEnd() override;
20418316Swollman
20518316Swollman  size_t CalculateNumChildren() override;
20618316Swollman
20718316Swollman  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
20846303Smarkm
20946303Smarkm  bool Update() override;
21046303Smarkm
21146303Smarkm  bool MightHaveChildren() override;
21246303Smarkm
21346303Smarkm  size_t GetIndexOfChildWithName(ConstString name) override;
21418316Swollman};
21518316Swollman} // namespace formatters
21618316Swollman} // namespace lldb_private
21718316Swollman
21819880Swollmantemplate <bool cf_style>
21946303Smarkmbool lldb_private::formatters::NSSetSummaryProvider(
22018316Swollman    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
22119880Swollman  static ConstString g_TypeHint("NSSet");
22218316Swollman
22319880Swollman  ProcessSP process_sp = valobj.GetProcessSP();
22419880Swollman  if (!process_sp)
22519880Swollman    return false;
22618316Swollman
22718316Swollman  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
22819880Swollman
22918316Swollman  if (!runtime)
23018316Swollman    return false;
23118316Swollman
23218316Swollman  ObjCLanguageRuntime::ClassDescriptorSP descriptor(
23319880Swollman      runtime->GetClassDescriptor(valobj));
23418316Swollman
23518316Swollman  if (!descriptor || !descriptor->IsValid())
23618316Swollman    return false;
23718316Swollman
23818316Swollman  uint32_t ptr_size = process_sp->GetAddressByteSize();
23918316Swollman  bool is_64bit = (ptr_size == 8);
24019880Swollman
24118316Swollman  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
24218316Swollman
24318316Swollman  if (!valobj_addr)
24418316Swollman    return false;
24518316Swollman
24646303Smarkm  uint64_t value = 0;
24746303Smarkm
24846303Smarkm  ConstString class_name_cs = descriptor->GetClassName();
24946303Smarkm  const char *class_name = class_name_cs.GetCString();
25046303Smarkm
25146303Smarkm  if (!class_name || !*class_name)
25290868Smike    return false;
25390868Smike
25418316Swollman  if (!strcmp(class_name, "__NSSetI") ||
25518316Swollman      !strcmp(class_name, "__NSOrderedSetI")) {
25646303Smarkm    Status error;
25718316Swollman    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
25818316Swollman                                                      ptr_size, 0, error);
25918316Swollman    if (error.Fail())
26018316Swollman      return false;
26118316Swollman    value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
26218316Swollman  } else if (!strcmp(class_name, "__NSSetM")) {
26318316Swollman    AppleObjCRuntime *apple_runtime =
26418316Swollman        llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
26518316Swollman    Status error;
26619880Swollman    if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
26718316Swollman      value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error);
26818316Swollman    } else {
26918316Swollman      value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
27018316Swollman                                                        ptr_size, 0, error);
27118316Swollman      value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
27218316Swollman    }
27318316Swollman    if (error.Fail())
27418316Swollman      return false;
27518316Swollman  } else {
27618316Swollman    auto &map(NSSet_Additionals::GetAdditionalSummaries());
27719880Swollman    auto iter = map.find(class_name_cs), end = map.end();
27818316Swollman    if (iter != end)
27918316Swollman      return iter->second(valobj, stream, options);
28018316Swollman    else
28118316Swollman      return false;
28218316Swollman  }
28319880Swollman
28418316Swollman  std::string prefix, suffix;
28518316Swollman  if (Language *language = Language::FindPlugin(options.GetLanguage())) {
28618316Swollman    if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
28718316Swollman                                            suffix)) {
28819880Swollman      prefix.clear();
28919880Swollman      suffix.clear();
29018316Swollman    }
29118316Swollman  }
29218316Swollman
29318316Swollman  stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
29418316Swollman                value == 1 ? "" : "s", suffix.c_str());
29518316Swollman  return true;
29618316Swollman}
29718316Swollman
29818316SwollmanSyntheticChildrenFrontEnd *
29918316Swollmanlldb_private::formatters::NSSetSyntheticFrontEndCreator(
30018316Swollman    CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
30118316Swollman  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
30219880Swollman  if (!process_sp)
30318316Swollman    return nullptr;
30418316Swollman  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
30518316Swollman  if (!runtime)
30618316Swollman    return nullptr;
30719880Swollman
30819880Swollman  CompilerType valobj_type(valobj_sp->GetCompilerType());
30918316Swollman  Flags flags(valobj_type.GetTypeInfo());
31018316Swollman
31118316Swollman  if (flags.IsClear(eTypeIsPointer)) {
31218316Swollman    Status error;
31318316Swollman    valobj_sp = valobj_sp->AddressOf(error);
31418316Swollman    if (error.Fail() || !valobj_sp)
31519880Swollman      return nullptr;
31618316Swollman  }
317126250Sbms
31818316Swollman  ObjCLanguageRuntime::ClassDescriptorSP descriptor(
31919880Swollman      runtime->GetClassDescriptor(*valobj_sp));
32018316Swollman
32118316Swollman  if (!descriptor || !descriptor->IsValid())
32218316Swollman    return nullptr;
32346303Smarkm
32446303Smarkm  ConstString class_name_cs = descriptor->GetClassName();
32518316Swollman  const char *class_name = class_name_cs.GetCString();
32618316Swollman
32718316Swollman  if (!class_name || !*class_name)
32846303Smarkm    return nullptr;
32919880Swollman
33046303Smarkm  if (!strcmp(class_name, "__NSSetI") ||
33119880Swollman      !strcmp(class_name, "__NSOrderedSetI")) {
33219880Swollman    return (new NSSetISyntheticFrontEnd(valobj_sp));
33318316Swollman  } else if (!strcmp(class_name, "__NSSetM")) {
33419880Swollman    AppleObjCRuntime *apple_runtime =
33519880Swollman        llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
33619880Swollman    if (apple_runtime) {
33719880Swollman      if (apple_runtime->GetFoundationVersion() >= 1437)
33819880Swollman        return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp));
33919880Swollman      else if (apple_runtime->GetFoundationVersion() >= 1428)
34018316Swollman        return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp));
34119880Swollman      else
34219880Swollman        return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
34319880Swollman    } else {
34419880Swollman      return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
34518316Swollman    }
34618316Swollman  } else {
34719880Swollman    auto &map(NSSet_Additionals::GetAdditionalSynthetics());
34819880Swollman    auto iter = map.find(class_name_cs), end = map.end();
34919880Swollman    if (iter != end)
35019880Swollman      return iter->second(synth, valobj_sp);
35119880Swollman    return nullptr;
35219880Swollman  }
353190711Sphk}
35418316Swollman
35518316Swollmanlldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(
35619880Swollman    lldb::ValueObjectSP valobj_sp)
35719880Swollman    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
35819880Swollman      m_data_32(nullptr), m_data_64(nullptr) {
35919880Swollman  if (valobj_sp)
36018316Swollman    Update();
36118316Swollman}
36220339Swollman
36320339Swollmanlldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {
36418316Swollman  delete m_data_32;
36518316Swollman  m_data_32 = nullptr;
36618316Swollman  delete m_data_64;
36746303Smarkm  m_data_64 = nullptr;
36818316Swollman}
36920339Swollman
37046303Smarkmsize_t
37146303Smarkmlldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(
37246303Smarkm    ConstString name) {
37346303Smarkm  const char *item_name = name.GetCString();
37446303Smarkm  uint32_t idx = ExtractIndexFromString(item_name);
37519880Swollman  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
37646303Smarkm    return UINT32_MAX;
37746303Smarkm  return idx;
37819880Swollman}
37919880Swollman
38019880Swollmansize_t
38119880Swollmanlldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {
38219880Swollman  if (!m_data_32 && !m_data_64)
38319880Swollman    return 0;
38420339Swollman  return (m_data_32 ? m_data_32->_used : m_data_64->_used);
38519880Swollman}
38619880Swollman
38719880Swollmanbool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
38819880Swollman  m_children.clear();
38937815Sphk  delete m_data_32;
39019880Swollman  m_data_32 = nullptr;
39119880Swollman  delete m_data_64;
39219880Swollman  m_data_64 = nullptr;
39319880Swollman  m_ptr_size = 0;
39419880Swollman  ValueObjectSP valobj_sp = m_backend.GetSP();
39519880Swollman  if (!valobj_sp)
39619880Swollman    return false;
39719880Swollman  if (!valobj_sp)
39819880Swollman    return false;
39919880Swollman  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
40019880Swollman  Status error;
40119880Swollman  if (valobj_sp->IsPointerType()) {
40219880Swollman    valobj_sp = valobj_sp->Dereference(error);
40319880Swollman    if (error.Fail() || !valobj_sp)
40419880Swollman      return false;
40519880Swollman  }
40619880Swollman  error.Clear();
40719880Swollman  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
40819880Swollman  if (!process_sp)
40919880Swollman    return false;
41019880Swollman  m_ptr_size = process_sp->GetAddressByteSize();
41119880Swollman  uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
41219880Swollman  if (m_ptr_size == 4) {
41319880Swollman    m_data_32 = new DataDescriptor_32();
41419880Swollman    process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
41519880Swollman                           error);
41619880Swollman  } else {
41719880Swollman    m_data_64 = new DataDescriptor_64();
41820339Swollman    process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
41920339Swollman                           error);
42020339Swollman  }
42146303Smarkm  if (error.Fail())
42219880Swollman    return false;
42346303Smarkm  m_data_ptr = data_location + m_ptr_size;
42446303Smarkm  return false;
42519880Swollman}
42619880Swollman
42719880Swollmanbool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() {
42819880Swollman  return true;
42919880Swollman}
43019880Swollman
43119880Swollmanlldb::ValueObjectSP
43219880Swollmanlldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) {
43319880Swollman  uint32_t num_children = CalculateNumChildren();
43419880Swollman
43519880Swollman  if (idx >= num_children)
43619880Swollman    return lldb::ValueObjectSP();
43719880Swollman
43819880Swollman  ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
43919880Swollman  if (!process_sp)
44046303Smarkm    return lldb::ValueObjectSP();
44119880Swollman
44219880Swollman  if (m_children.empty()) {
44319880Swollman    // do the scan phase
44419880Swollman    lldb::addr_t obj_at_idx = 0;
44519880Swollman
44620339Swollman    uint32_t tries = 0;
44719880Swollman    uint32_t test_idx = 0;
44819880Swollman
44919880Swollman    while (tries < num_children) {
45046303Smarkm      obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
45146303Smarkm      if (!process_sp)
45246303Smarkm        return lldb::ValueObjectSP();
45346303Smarkm      Status error;
45446303Smarkm      obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
45546303Smarkm      if (error.Fail())
45619880Swollman        return lldb::ValueObjectSP();
45719880Swollman
45820339Swollman      test_idx++;
45919880Swollman
46019880Swollman      if (!obj_at_idx)
46119880Swollman        continue;
46219880Swollman      tries++;
46319880Swollman
46419880Swollman      SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
46519880Swollman
46620339Swollman      m_children.push_back(descriptor);
46720339Swollman    }
46819880Swollman  }
46946303Smarkm
47020339Swollman  if (idx >= m_children.size()) // should never happen
47120339Swollman    return lldb::ValueObjectSP();
47220339Swollman
47346303Smarkm  SetItemDescriptor &set_item = m_children[idx];
47420339Swollman  if (!set_item.valobj_sp) {
47519880Swollman    auto ptr_size = process_sp->GetAddressByteSize();
47619880Swollman    DataBufferHeap buffer(ptr_size, 0);
47719880Swollman    switch (ptr_size) {
47820339Swollman    case 0: // architecture has no clue?? - fail
47919880Swollman      return lldb::ValueObjectSP();
48019880Swollman    case 4:
48119880Swollman      *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
482190718Sphk      break;
48320339Swollman    case 8:
48446303Smarkm      *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
48519880Swollman      break;
48620339Swollman    default:
48720339Swollman      assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
48820339Swollman    }
48920339Swollman    StreamString idx_name;
49020339Swollman    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
49119880Swollman
49246303Smarkm    DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
49320339Swollman                       process_sp->GetByteOrder(),
49420339Swollman                       process_sp->GetAddressByteSize());
49519880Swollman
49620339Swollman    set_item.valobj_sp = CreateValueObjectFromData(
49720339Swollman        idx_name.GetString(), data, m_exe_ctx_ref,
49820339Swollman        m_backend.GetCompilerType().GetBasicTypeFromAST(
49920339Swollman            lldb::eBasicTypeObjCID));
50019880Swollman  }
50120339Swollman  return set_item.valobj_sp;
50220339Swollman}
50320339Swollman
50420339Swollmantemplate <typename D32, typename D64>
50519880Swollmanlldb_private::formatters::
50620339Swollman  GenericNSSetMSyntheticFrontEnd<D32, D64>::GenericNSSetMSyntheticFrontEnd(
50719880Swollman    lldb::ValueObjectSP valobj_sp)
50819880Swollman    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
50919880Swollman      m_data_32(nullptr), m_data_64(nullptr) {
51019880Swollman  if (valobj_sp)
51120339Swollman    Update();
51219880Swollman}
51319880Swollman
51420339Swollmantemplate <typename D32, typename D64>
51520339Swollmanlldb_private::formatters::
51619880Swollman  GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd() {
51719880Swollman  delete m_data_32;
51819880Swollman  m_data_32 = nullptr;
51919880Swollman  delete m_data_64;
52020339Swollman  m_data_64 = nullptr;
52119880Swollman}
52220339Swollman
52320339Swollmantemplate <typename D32, typename D64>
52420339Swollmansize_t
52520339Swollmanlldb_private::formatters::
52620339Swollman  GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName(
52720339Swollman    ConstString name) {
52820339Swollman  const char *item_name = name.GetCString();
52920339Swollman  uint32_t idx = ExtractIndexFromString(item_name);
53020339Swollman  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
53120339Swollman    return UINT32_MAX;
53220339Swollman  return idx;
53320339Swollman}
53420339Swollman
53520339Swollmantemplate <typename D32, typename D64>
53620339Swollmansize_t
53720339Swollmanlldb_private::formatters::
53819880Swollman  GenericNSSetMSyntheticFrontEnd<D32, D64>::CalculateNumChildren() {
53919880Swollman  if (!m_data_32 && !m_data_64)
54020339Swollman    return 0;
54120339Swollman  return (m_data_32 ? m_data_32->_used : m_data_64->_used);
54219880Swollman}
54346303Smarkm
54420339Swollmantemplate <typename D32, typename D64>
54519880Swollmanbool
54619880Swollmanlldb_private::formatters::
54719880Swollman  GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {
54846303Smarkm  m_children.clear();
54946303Smarkm  ValueObjectSP valobj_sp = m_backend.GetSP();
55046303Smarkm  m_ptr_size = 0;
55146303Smarkm  delete m_data_32;
55246303Smarkm  m_data_32 = nullptr;
55346303Smarkm  delete m_data_64;
55446303Smarkm  m_data_64 = nullptr;
55546303Smarkm  if (!valobj_sp)
55646303Smarkm    return false;
55746303Smarkm  if (!valobj_sp)
55819880Swollman    return false;
55919880Swollman  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
56046303Smarkm  Status error;
56120339Swollman  if (valobj_sp->IsPointerType()) {
56220339Swollman    valobj_sp = valobj_sp->Dereference(error);
56318316Swollman    if (error.Fail() || !valobj_sp)
56419880Swollman      return false;
56519880Swollman  }
56618316Swollman  error.Clear();
56718316Swollman  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
56818316Swollman  if (!process_sp)
56918316Swollman    return false;
57046303Smarkm  m_ptr_size = process_sp->GetAddressByteSize();
57119880Swollman  uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
57219880Swollman  if (m_ptr_size == 4) {
57346303Smarkm    m_data_32 = new D32();
57446303Smarkm    process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
57546303Smarkm                           error);
57646303Smarkm  } else {
57718316Swollman    m_data_64 = new D64();
57818316Swollman    process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
57946303Smarkm                           error);
58019880Swollman  }
58135306Sphk  if (error.Fail())
58246303Smarkm    return false;
58346303Smarkm  return false;
58446303Smarkm}
58546303Smarkm
58618316Swollmantemplate <typename D32, typename D64>
58746303Smarkmbool
58846303Smarkmlldb_private::formatters::
58918316Swollman  GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() {
59018316Swollman  return true;
59118316Swollman}
59246303Smarkm
59318316Swollmantemplate <typename D32, typename D64>
59446303Smarkmlldb::ValueObjectSP
59518316Swollmanlldb_private::formatters::
59618316Swollman  GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(size_t idx) {
59718316Swollman  lldb::addr_t m_objs_addr =
59846303Smarkm      (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
59918316Swollman
60090868Smike  uint32_t num_children = CalculateNumChildren();
60118316Swollman
60218316Swollman  if (idx >= num_children)
60318316Swollman    return lldb::ValueObjectSP();
60418316Swollman
60518316Swollman  ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
60646303Smarkm  if (!process_sp)
60746303Smarkm    return lldb::ValueObjectSP();
60846303Smarkm
60946303Smarkm  if (m_children.empty()) {
61046303Smarkm    // do the scan phase
61146303Smarkm    lldb::addr_t obj_at_idx = 0;
61246303Smarkm
61346303Smarkm    uint32_t tries = 0;
61446303Smarkm    uint32_t test_idx = 0;
61546303Smarkm
61646303Smarkm    while (tries < num_children) {
61746303Smarkm      obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
61846303Smarkm      if (!process_sp)
61946303Smarkm        return lldb::ValueObjectSP();
62046303Smarkm      Status error;
62146303Smarkm      obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
62246303Smarkm      if (error.Fail())
62346303Smarkm        return lldb::ValueObjectSP();
62446303Smarkm
62546303Smarkm      test_idx++;
62646303Smarkm
62746303Smarkm      if (!obj_at_idx)
62846303Smarkm        continue;
62946303Smarkm      tries++;
63046303Smarkm
63118316Swollman      SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
63246303Smarkm
63346303Smarkm      m_children.push_back(descriptor);
63419880Swollman    }
63519880Swollman  }
63646303Smarkm
63719880Swollman  if (idx >= m_children.size()) // should never happen
63846303Smarkm    return lldb::ValueObjectSP();
63919880Swollman
64019880Swollman  SetItemDescriptor &set_item = m_children[idx];
64119880Swollman  if (!set_item.valobj_sp) {
64246303Smarkm    auto ptr_size = process_sp->GetAddressByteSize();
64319880Swollman    DataBufferHeap buffer(ptr_size, 0);
64446303Smarkm    switch (ptr_size) {
645190718Sphk    case 0: // architecture has no clue?? - fail
646190718Sphk      return lldb::ValueObjectSP();
64719880Swollman    case 4:
64846303Smarkm      *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
64946303Smarkm      break;
65046303Smarkm    case 8:
65146303Smarkm      *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
65246303Smarkm      break;
65346303Smarkm    default:
65446303Smarkm      assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
65546303Smarkm    }
65646303Smarkm    StreamString idx_name;
65746303Smarkm    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
65846303Smarkm
65919880Swollman    DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
66019880Swollman                       process_sp->GetByteOrder(),
66118316Swollman                       process_sp->GetAddressByteSize());
66246303Smarkm
66346303Smarkm    set_item.valobj_sp = CreateValueObjectFromData(
66419880Swollman        idx_name.GetString(), data, m_exe_ctx_ref,
66518316Swollman        m_backend.GetCompilerType().GetBasicTypeFromAST(
66619880Swollman            lldb::eBasicTypeObjCID));
66719880Swollman  }
66819880Swollman  return set_item.valobj_sp;
66919880Swollman}
67019880Swollman
67119880Swollmantemplate bool lldb_private::formatters::NSSetSummaryProvider<true>(
67219880Swollman    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
67320339Swollman
67419880Swollmantemplate bool lldb_private::formatters::NSSetSummaryProvider<false>(
67546303Smarkm    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
67619880Swollman