1292932Sdim//===-- NSArray.cpp ---------------------------------------------*- C++ -*-===//
2292932Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6292932Sdim//
7292932Sdim//===----------------------------------------------------------------------===//
8292932Sdim
9292932Sdim#include "clang/AST/ASTContext.h"
10292932Sdim
11292932Sdim#include "Cocoa.h"
12292932Sdim
13314564Sdim#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
14353358Sdim
15292932Sdim#include "lldb/Core/ValueObject.h"
16292932Sdim#include "lldb/Core/ValueObjectConstResult.h"
17292932Sdim#include "lldb/DataFormatters/FormattersHelpers.h"
18292932Sdim#include "lldb/Expression/FunctionCaller.h"
19292932Sdim#include "lldb/Symbol/ClangASTContext.h"
20292932Sdim#include "lldb/Target/Language.h"
21292932Sdim#include "lldb/Target/Target.h"
22321369Sdim#include "lldb/Utility/DataBufferHeap.h"
23321369Sdim#include "lldb/Utility/Endian.h"
24321369Sdim#include "lldb/Utility/Status.h"
25321369Sdim#include "lldb/Utility/Stream.h"
26292932Sdim
27292932Sdimusing namespace lldb;
28292932Sdimusing namespace lldb_private;
29292932Sdimusing namespace lldb_private::formatters;
30292932Sdim
31314564Sdimnamespace lldb_private {
32314564Sdimnamespace formatters {
33314564Sdimstd::map<ConstString, CXXFunctionSummaryFormat::Callback> &
34314564SdimNSArray_Additionals::GetAdditionalSummaries() {
35314564Sdim  static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
36314564Sdim  return g_map;
37314564Sdim}
38292932Sdim
39314564Sdimstd::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
40314564SdimNSArray_Additionals::GetAdditionalSynthetics() {
41314564Sdim  static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
42314564Sdim      g_map;
43314564Sdim  return g_map;
44314564Sdim}
45292932Sdim
46327952Sdimclass NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd {
47314564Sdimpublic:
48327952Sdim  NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp);
49292932Sdim
50327952Sdim  ~NSArrayMSyntheticFrontEndBase() override = default;
51292932Sdim
52314564Sdim  size_t CalculateNumChildren() override;
53292932Sdim
54314564Sdim  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
55292932Sdim
56314564Sdim  bool Update() override = 0;
57292932Sdim
58314564Sdim  bool MightHaveChildren() override;
59292932Sdim
60353358Sdim  size_t GetIndexOfChildWithName(ConstString name) override;
61292932Sdim
62314564Sdimprotected:
63314564Sdim  virtual lldb::addr_t GetDataAddress() = 0;
64292932Sdim
65314564Sdim  virtual uint64_t GetUsedCount() = 0;
66292932Sdim
67314564Sdim  virtual uint64_t GetOffset() = 0;
68292932Sdim
69314564Sdim  virtual uint64_t GetSize() = 0;
70292932Sdim
71314564Sdim  ExecutionContextRef m_exe_ctx_ref;
72314564Sdim  uint8_t m_ptr_size;
73314564Sdim  CompilerType m_id_type;
74314564Sdim};
75292932Sdim
76327952Sdimtemplate <typename D32, typename D64>
77327952Sdimclass GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase {
78314564Sdimpublic:
79327952Sdim  GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
80292932Sdim
81327952Sdim  ~GenericNSArrayMSyntheticFrontEnd() override;
82309124Sdim
83314564Sdim  bool Update() override;
84314564Sdim
85314564Sdimprotected:
86314564Sdim  lldb::addr_t GetDataAddress() override;
87314564Sdim
88314564Sdim  uint64_t GetUsedCount() override;
89314564Sdim
90314564Sdim  uint64_t GetOffset() override;
91314564Sdim
92314564Sdim  uint64_t GetSize() override;
93314564Sdim
94314564Sdimprivate:
95327952Sdim  D32 *m_data_32;
96327952Sdim  D64 *m_data_64;
97327952Sdim};
98327952Sdim
99327952Sdimnamespace Foundation1010 {
100314564Sdim  struct DataDescriptor_32 {
101314564Sdim    uint32_t _used;
102314564Sdim    uint32_t _offset;
103314564Sdim    uint32_t _size : 28;
104314564Sdim    uint64_t _priv1 : 4;
105314564Sdim    uint32_t _priv2;
106314564Sdim    uint32_t _data;
107314564Sdim  };
108327952Sdim
109314564Sdim  struct DataDescriptor_64 {
110314564Sdim    uint64_t _used;
111314564Sdim    uint64_t _offset;
112314564Sdim    uint64_t _size : 60;
113314564Sdim    uint64_t _priv1 : 4;
114314564Sdim    uint32_t _priv2;
115314564Sdim    uint64_t _data;
116314564Sdim  };
117327952Sdim
118327952Sdim  using NSArrayMSyntheticFrontEnd =
119327952Sdim      GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
120327952Sdim}
121327952Sdim
122327952Sdimnamespace Foundation1428 {
123321369Sdim  struct DataDescriptor_32 {
124327952Sdim    uint32_t _used;
125327952Sdim    uint32_t _offset;
126327952Sdim    uint32_t _size;
127327952Sdim    uint32_t _data;
128321369Sdim  };
129327952Sdim
130321369Sdim  struct DataDescriptor_64 {
131327952Sdim    uint64_t _used;
132327952Sdim    uint64_t _offset;
133327952Sdim    uint64_t _size;
134327952Sdim    uint64_t _data;
135321369Sdim  };
136327952Sdim
137327952Sdim  using NSArrayMSyntheticFrontEnd =
138327952Sdim      GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
139327952Sdim}
140327952Sdim
141327952Sdimnamespace Foundation1437 {
142327952Sdim  template <typename PtrType>
143327952Sdim  struct DataDescriptor {
144327952Sdim    PtrType _cow;
145327952Sdim    // __deque
146327952Sdim    PtrType _data;
147327952Sdim    uint32_t _offset;
148327952Sdim    uint32_t _size;
149353358Sdim    uint32_t _muts;
150353358Sdim    uint32_t _used;
151327952Sdim  };
152327952Sdim
153327952Sdim  using NSArrayMSyntheticFrontEnd =
154327952Sdim     GenericNSArrayMSyntheticFrontEnd<
155327952Sdim        DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>;
156327952Sdim
157327952Sdim  template <typename DD>
158327952Sdim  uint64_t
159327952Sdim  __NSArrayMSize_Impl(lldb_private::Process &process,
160327952Sdim                      lldb::addr_t valobj_addr, Status &error) {
161327952Sdim    const lldb::addr_t start_of_descriptor =
162327952Sdim    valobj_addr + process.GetAddressByteSize();
163327952Sdim    DD descriptor = DD();
164327952Sdim    process.ReadMemory(start_of_descriptor, &descriptor,
165327952Sdim                       sizeof(descriptor), error);
166327952Sdim    if (error.Fail()) {
167327952Sdim      return 0;
168327952Sdim    }
169327952Sdim    return descriptor._used;
170327952Sdim  }
171327952Sdim
172327952Sdim  uint64_t
173327952Sdim  __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
174327952Sdim                 Status &error) {
175327952Sdim    if (process.GetAddressByteSize() == 4) {
176327952Sdim      return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr,
177327952Sdim                                                           error);
178327952Sdim    } else {
179327952Sdim      return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr,
180327952Sdim                                                           error);
181327952Sdim    }
182327952Sdim  }
183321369Sdim
184327952Sdim}
185321369Sdim
186344779Sdimnamespace CallStackArray {
187344779Sdimstruct DataDescriptor_32 {
188344779Sdim  uint32_t _data;
189344779Sdim  uint32_t _used;
190344779Sdim  uint32_t _offset;
191344779Sdim  const uint32_t _size = 0;
192344779Sdim};
193344779Sdim
194344779Sdimstruct DataDescriptor_64 {
195344779Sdim  uint64_t _data;
196344779Sdim  uint64_t _used;
197344779Sdim  uint64_t _offset;
198344779Sdim  const uint64_t _size = 0;
199344779Sdim};
200344779Sdim
201344779Sdimusing NSCallStackArraySyntheticFrontEnd =
202344779Sdim    GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
203344779Sdim} // namespace CallStackArray
204344779Sdim
205327952Sdimtemplate <typename D32, typename D64, bool Inline>
206327952Sdimclass GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
207321369Sdimpublic:
208327952Sdim  GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
209321369Sdim
210327952Sdim  ~GenericNSArrayISyntheticFrontEnd() override;
211321369Sdim
212314564Sdim  size_t CalculateNumChildren() override;
213314564Sdim
214314564Sdim  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
215314564Sdim
216314564Sdim  bool Update() override;
217314564Sdim
218314564Sdim  bool MightHaveChildren() override;
219314564Sdim
220353358Sdim  size_t GetIndexOfChildWithName(ConstString name) override;
221314564Sdim
222314564Sdimprivate:
223314564Sdim  ExecutionContextRef m_exe_ctx_ref;
224314564Sdim  uint8_t m_ptr_size;
225327952Sdim
226327952Sdim  D32 *m_data_32;
227327952Sdim  D64 *m_data_64;
228314564Sdim  CompilerType m_id_type;
229314564Sdim};
230327952Sdim
231327952Sdimnamespace Foundation1300 {
232327952Sdim    struct IDD32 {
233327952Sdim        uint32_t used;
234327952Sdim        uint32_t list;
235327952Sdim    };
236327952Sdim
237327952Sdim    struct IDD64 {
238327952Sdim        uint64_t used;
239327952Sdim        uint64_t list;
240327952Sdim    };
241327952Sdim
242327952Sdim    using NSArrayISyntheticFrontEnd =
243327952Sdim        GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
244327952Sdim}
245314564Sdim
246327952Sdimnamespace Foundation1430 {
247327952Sdim    using NSArrayISyntheticFrontEnd =
248327952Sdim        Foundation1428::NSArrayMSyntheticFrontEnd;
249327952Sdim}
250321369Sdim
251327952Sdimnamespace Foundation1436 {
252327952Sdim    struct IDD32 {
253327952Sdim        uint32_t used;
254327952Sdim        uint32_t list; // in Inline cases, this is the first element
255327952Sdim    };
256327952Sdim
257327952Sdim    struct IDD64 {
258327952Sdim        uint64_t used;
259327952Sdim        uint64_t list; // in Inline cases, this is the first element
260327952Sdim    };
261327952Sdim
262327952Sdim    using NSArrayI_TransferSyntheticFrontEnd =
263327952Sdim        GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>;
264321369Sdim
265327952Sdim    using NSArrayISyntheticFrontEnd =
266327952Sdim        GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
267327952Sdim
268327952Sdim    using NSFrozenArrayMSyntheticFrontEnd =
269327952Sdim        Foundation1437::NSArrayMSyntheticFrontEnd;
270321369Sdim
271327952Sdim    uint64_t
272327952Sdim    __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
273327952Sdim                         Status &error) {
274327952Sdim      return Foundation1437::__NSArrayMSize(process, valobj_addr, error);
275327952Sdim    }
276327952Sdim}
277321369Sdim
278314564Sdimclass NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
279314564Sdimpublic:
280314564Sdim  NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
281314564Sdim
282314564Sdim  ~NSArray0SyntheticFrontEnd() override = default;
283314564Sdim
284314564Sdim  size_t CalculateNumChildren() override;
285314564Sdim
286314564Sdim  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
287314564Sdim
288314564Sdim  bool Update() override;
289314564Sdim
290314564Sdim  bool MightHaveChildren() override;
291314564Sdim
292353358Sdim  size_t GetIndexOfChildWithName(ConstString name) override;
293314564Sdim};
294314564Sdim
295314564Sdimclass NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
296314564Sdimpublic:
297314564Sdim  NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
298314564Sdim
299314564Sdim  ~NSArray1SyntheticFrontEnd() override = default;
300314564Sdim
301314564Sdim  size_t CalculateNumChildren() override;
302314564Sdim
303314564Sdim  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
304314564Sdim
305314564Sdim  bool Update() override;
306314564Sdim
307314564Sdim  bool MightHaveChildren() override;
308314564Sdim
309353358Sdim  size_t GetIndexOfChildWithName(ConstString name) override;
310314564Sdim};
311314564Sdim} // namespace formatters
312292932Sdim} // namespace lldb_private
313292932Sdim
314314564Sdimbool lldb_private::formatters::NSArraySummaryProvider(
315314564Sdim    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
316314564Sdim  static ConstString g_TypeHint("NSArray");
317314564Sdim
318314564Sdim  ProcessSP process_sp = valobj.GetProcessSP();
319314564Sdim  if (!process_sp)
320314564Sdim    return false;
321314564Sdim
322353358Sdim  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
323314564Sdim
324314564Sdim  if (!runtime)
325314564Sdim    return false;
326314564Sdim
327314564Sdim  ObjCLanguageRuntime::ClassDescriptorSP descriptor(
328314564Sdim      runtime->GetClassDescriptor(valobj));
329314564Sdim
330314564Sdim  if (!descriptor || !descriptor->IsValid())
331314564Sdim    return false;
332314564Sdim
333314564Sdim  uint32_t ptr_size = process_sp->GetAddressByteSize();
334314564Sdim
335314564Sdim  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
336314564Sdim
337314564Sdim  if (!valobj_addr)
338314564Sdim    return false;
339314564Sdim
340314564Sdim  uint64_t value = 0;
341314564Sdim
342314564Sdim  ConstString class_name(descriptor->GetClassName());
343314564Sdim
344314564Sdim  static const ConstString g_NSArrayI("__NSArrayI");
345314564Sdim  static const ConstString g_NSArrayM("__NSArrayM");
346327952Sdim  static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
347327952Sdim  static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
348314564Sdim  static const ConstString g_NSArray0("__NSArray0");
349314564Sdim  static const ConstString g_NSArray1("__NSSingleObjectArrayI");
350314564Sdim  static const ConstString g_NSArrayCF("__NSCFArray");
351321369Sdim  static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
352321369Sdim  static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
353344779Sdim  static const ConstString g_NSCallStackArray("_NSCallStackArray");
354314564Sdim
355314564Sdim  if (class_name.IsEmpty())
356314564Sdim    return false;
357314564Sdim
358314564Sdim  if (class_name == g_NSArrayI) {
359321369Sdim    Status error;
360314564Sdim    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
361314564Sdim                                                      ptr_size, 0, error);
362314564Sdim    if (error.Fail())
363314564Sdim      return false;
364314564Sdim  } else if (class_name == g_NSArrayM) {
365327952Sdim    AppleObjCRuntime *apple_runtime =
366327952Sdim    llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
367321369Sdim    Status error;
368327952Sdim    if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
369327952Sdim      value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error);
370327952Sdim    } else {
371327952Sdim      value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
372327952Sdim                                                        ptr_size, 0, error);
373327952Sdim    }
374327952Sdim    if (error.Fail())
375327952Sdim      return false;
376327952Sdim  } else if (class_name == g_NSArrayI_Transfer) {
377327952Sdim    Status error;
378314564Sdim    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
379314564Sdim                                                      ptr_size, 0, error);
380314564Sdim    if (error.Fail())
381314564Sdim      return false;
382327952Sdim  } else if (class_name == g_NSFrozenArrayM) {
383327952Sdim    Status error;
384327952Sdim    value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error);
385327952Sdim    if (error.Fail())
386327952Sdim      return false;
387321369Sdim  } else if (class_name == g_NSArrayMLegacy) {
388321369Sdim    Status error;
389321369Sdim    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
390321369Sdim                                                      ptr_size, 0, error);
391321369Sdim    if (error.Fail())
392321369Sdim      return false;
393321369Sdim  } else if (class_name == g_NSArrayMImmutable) {
394321369Sdim    Status error;
395321369Sdim    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
396321369Sdim                                                      ptr_size, 0, error);
397321369Sdim    if (error.Fail())
398321369Sdim      return false;
399314564Sdim  } else if (class_name == g_NSArray0) {
400314564Sdim    value = 0;
401314564Sdim  } else if (class_name == g_NSArray1) {
402314564Sdim    value = 1;
403344779Sdim  } else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) {
404344779Sdim    // __NSCFArray and _NSCallStackArray store the number of elements as a
405344779Sdim    // pointer-sized value at offset `2 * ptr_size`.
406321369Sdim    Status error;
407314564Sdim    value = process_sp->ReadUnsignedIntegerFromMemory(
408314564Sdim        valobj_addr + 2 * ptr_size, ptr_size, 0, error);
409314564Sdim    if (error.Fail())
410314564Sdim      return false;
411314564Sdim  } else {
412314564Sdim    auto &map(NSArray_Additionals::GetAdditionalSummaries());
413314564Sdim    auto iter = map.find(class_name), end = map.end();
414314564Sdim    if (iter != end)
415314564Sdim      return iter->second(valobj, stream, options);
416292932Sdim    else
417314564Sdim      return false;
418314564Sdim  }
419292932Sdim
420314564Sdim  std::string prefix, suffix;
421314564Sdim  if (Language *language = Language::FindPlugin(options.GetLanguage())) {
422314564Sdim    if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
423314564Sdim                                            suffix)) {
424314564Sdim      prefix.clear();
425314564Sdim      suffix.clear();
426292932Sdim    }
427314564Sdim  }
428292932Sdim
429314564Sdim  stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
430314564Sdim                value == 1 ? "" : "s", suffix.c_str());
431314564Sdim  return true;
432292932Sdim}
433292932Sdim
434327952Sdimlldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontEndBase(
435314564Sdim    lldb::ValueObjectSP valobj_sp)
436314564Sdim    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
437314564Sdim      m_id_type() {
438314564Sdim  if (valobj_sp) {
439360784Sdim    auto *clang_ast_context = ClangASTContext::GetScratch(
440360784Sdim        *valobj_sp->GetExecutionContextRef().GetTargetSP());
441360784Sdim    if (clang_ast_context)
442360784Sdim      m_id_type = CompilerType(
443360784Sdim          clang_ast_context,
444360784Sdim          clang_ast_context->getASTContext().ObjCBuiltinIdTy.getAsOpaquePtr());
445314564Sdim    if (valobj_sp->GetProcessSP())
446314564Sdim      m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
447314564Sdim  }
448292932Sdim}
449292932Sdim
450327952Sdimtemplate <typename D32, typename D64>
451327952Sdimlldb_private::formatters::
452327952Sdim  GenericNSArrayMSyntheticFrontEnd<D32, D64>::
453327952Sdim    GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
454327952Sdim    : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr),
455314564Sdim      m_data_64(nullptr) {}
456314564Sdim
457292932Sdimsize_t
458327952Sdimlldb_private::formatters::NSArrayMSyntheticFrontEndBase::CalculateNumChildren() {
459314564Sdim  return GetUsedCount();
460292932Sdim}
461292932Sdim
462292932Sdimlldb::ValueObjectSP
463327952Sdimlldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(
464314564Sdim    size_t idx) {
465314564Sdim  if (idx >= CalculateNumChildren())
466314564Sdim    return lldb::ValueObjectSP();
467314564Sdim  lldb::addr_t object_at_idx = GetDataAddress();
468314564Sdim  size_t pyhs_idx = idx;
469314564Sdim  pyhs_idx += GetOffset();
470314564Sdim  if (GetSize() <= pyhs_idx)
471314564Sdim    pyhs_idx -= GetSize();
472314564Sdim  object_at_idx += (pyhs_idx * m_ptr_size);
473314564Sdim  StreamString idx_name;
474314564Sdim  idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
475314564Sdim  return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
476314564Sdim                                      m_exe_ctx_ref, m_id_type);
477292932Sdim}
478292932Sdim
479327952Sdimtemplate <typename D32, typename D64>
480327952Sdimbool
481327952Sdimlldb_private::formatters::
482327952Sdim  GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {
483314564Sdim  ValueObjectSP valobj_sp = m_backend.GetSP();
484314564Sdim  m_ptr_size = 0;
485314564Sdim  delete m_data_32;
486314564Sdim  m_data_32 = nullptr;
487314564Sdim  delete m_data_64;
488314564Sdim  m_data_64 = nullptr;
489314564Sdim  if (!valobj_sp)
490292932Sdim    return false;
491314564Sdim  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
492321369Sdim  Status error;
493314564Sdim  error.Clear();
494314564Sdim  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
495314564Sdim  if (!process_sp)
496314564Sdim    return false;
497314564Sdim  m_ptr_size = process_sp->GetAddressByteSize();
498314564Sdim  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
499314564Sdim  if (m_ptr_size == 4) {
500327952Sdim    m_data_32 = new D32();
501327952Sdim    process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
502314564Sdim                           error);
503314564Sdim  } else {
504327952Sdim    m_data_64 = new D64();
505327952Sdim    process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
506314564Sdim                           error);
507314564Sdim  }
508314564Sdim  if (error.Fail())
509314564Sdim    return false;
510314564Sdim  return false;
511292932Sdim}
512292932Sdim
513327952Sdimbool
514327952Sdimlldb_private::formatters::NSArrayMSyntheticFrontEndBase::MightHaveChildren() {
515314564Sdim  return true;
516292932Sdim}
517292932Sdim
518292932Sdimsize_t
519327952Sdimlldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName(
520353358Sdim    ConstString name) {
521314564Sdim  const char *item_name = name.GetCString();
522314564Sdim  uint32_t idx = ExtractIndexFromString(item_name);
523314564Sdim  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
524314564Sdim    return UINT32_MAX;
525314564Sdim  return idx;
526292932Sdim}
527292932Sdim
528327952Sdimtemplate <typename D32, typename D64>
529327952Sdimlldb_private::formatters::
530327952Sdim  GenericNSArrayMSyntheticFrontEnd<D32, D64>::
531327952Sdim    ~GenericNSArrayMSyntheticFrontEnd() {
532314564Sdim  delete m_data_32;
533314564Sdim  m_data_32 = nullptr;
534314564Sdim  delete m_data_64;
535314564Sdim  m_data_64 = nullptr;
536292932Sdim}
537292932Sdim
538327952Sdimtemplate <typename D32, typename D64>
539292932Sdimlldb::addr_t
540327952Sdimlldb_private::formatters::
541327952Sdim  GenericNSArrayMSyntheticFrontEnd<D32, D64>::
542327952Sdim    GenericNSArrayMSyntheticFrontEnd::GetDataAddress() {
543314564Sdim  if (!m_data_32 && !m_data_64)
544314564Sdim    return LLDB_INVALID_ADDRESS;
545314564Sdim  return m_data_32 ? m_data_32->_data : m_data_64->_data;
546292932Sdim}
547292932Sdim
548327952Sdimtemplate <typename D32, typename D64>
549292932Sdimuint64_t
550327952Sdimlldb_private::formatters::
551327952Sdim  GenericNSArrayMSyntheticFrontEnd<D32, D64>::
552327952Sdim    GenericNSArrayMSyntheticFrontEnd::GetUsedCount() {
553314564Sdim  if (!m_data_32 && !m_data_64)
554314564Sdim    return 0;
555314564Sdim  return m_data_32 ? m_data_32->_used : m_data_64->_used;
556292932Sdim}
557292932Sdim
558327952Sdimtemplate <typename D32, typename D64>
559327952Sdimuint64_t
560327952Sdimlldb_private::formatters::
561327952Sdim  GenericNSArrayMSyntheticFrontEnd<D32, D64>::
562327952Sdim    GenericNSArrayMSyntheticFrontEnd::GetOffset() {
563314564Sdim  if (!m_data_32 && !m_data_64)
564314564Sdim    return 0;
565314564Sdim  return m_data_32 ? m_data_32->_offset : m_data_64->_offset;
566292932Sdim}
567292932Sdim
568327952Sdimtemplate <typename D32, typename D64>
569292932Sdimuint64_t
570327952Sdimlldb_private::formatters::
571327952Sdim  GenericNSArrayMSyntheticFrontEnd<D32, D64>::
572327952Sdim    GenericNSArrayMSyntheticFrontEnd::GetSize() {
573314564Sdim  if (!m_data_32 && !m_data_64)
574314564Sdim    return 0;
575314564Sdim  return m_data_32 ? m_data_32->_size : m_data_64->_size;
576292932Sdim}
577292932Sdim
578327952Sdimtemplate <typename D32, typename D64, bool Inline>
579327952Sdimlldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
580327952Sdim  GenericNSArrayISyntheticFrontEnd(
581314564Sdim    lldb::ValueObjectSP valobj_sp)
582314564Sdim    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
583321369Sdim      m_data_32(nullptr), m_data_64(nullptr) {
584321369Sdim  if (valobj_sp) {
585321369Sdim    CompilerType type = valobj_sp->GetCompilerType();
586321369Sdim    if (type) {
587360784Sdim      auto *clang_ast_context = ClangASTContext::GetScratch(
588360784Sdim          *valobj_sp->GetExecutionContextRef().GetTargetSP());
589360784Sdim      if (clang_ast_context)
590360784Sdim        m_id_type = clang_ast_context->GetType(
591360784Sdim            clang_ast_context->getASTContext().ObjCBuiltinIdTy);
592321369Sdim    }
593321369Sdim  }
594321369Sdim}
595321369Sdim
596327952Sdimtemplate <typename D32, typename D64, bool Inline>
597327952Sdimlldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
598327952Sdim  ~GenericNSArrayISyntheticFrontEnd() {
599321369Sdim  delete m_data_32;
600321369Sdim  m_data_32 = nullptr;
601321369Sdim  delete m_data_64;
602321369Sdim  m_data_64 = nullptr;
603321369Sdim}
604321369Sdim
605327952Sdimtemplate <typename D32, typename D64, bool Inline>
606321369Sdimsize_t
607327952Sdimlldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
608353358Sdim  GetIndexOfChildWithName(ConstString name) {
609321369Sdim  const char *item_name = name.GetCString();
610321369Sdim  uint32_t idx = ExtractIndexFromString(item_name);
611321369Sdim  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
612321369Sdim    return UINT32_MAX;
613321369Sdim  return idx;
614321369Sdim}
615321369Sdim
616327952Sdimtemplate <typename D32, typename D64, bool Inline>
617321369Sdimsize_t
618327952Sdimlldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
619327952Sdim  CalculateNumChildren() {
620321369Sdim  return m_data_32 ? m_data_32->used : m_data_64->used;
621321369Sdim}
622321369Sdim
623327952Sdimtemplate <typename D32, typename D64, bool Inline>
624327952Sdimbool
625327952Sdimlldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
626327952Sdim  Update() {
627321369Sdim  ValueObjectSP valobj_sp = m_backend.GetSP();
628321369Sdim  m_ptr_size = 0;
629321369Sdim  delete m_data_32;
630321369Sdim  m_data_32 = nullptr;
631321369Sdim  delete m_data_64;
632321369Sdim  m_data_64 = nullptr;
633321369Sdim  if (!valobj_sp)
634321369Sdim    return false;
635321369Sdim  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
636321369Sdim  Status error;
637321369Sdim  error.Clear();
638321369Sdim  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
639321369Sdim  if (!process_sp)
640321369Sdim    return false;
641321369Sdim  m_ptr_size = process_sp->GetAddressByteSize();
642321369Sdim  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
643321369Sdim  if (m_ptr_size == 4) {
644327952Sdim    m_data_32 = new D32();
645327952Sdim    process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
646321369Sdim                           error);
647321369Sdim  } else {
648327952Sdim    m_data_64 = new D64();
649327952Sdim    process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
650321369Sdim                           error);
651321369Sdim  }
652321369Sdim  if (error.Fail())
653321369Sdim    return false;
654321369Sdim  return false;
655321369Sdim}
656321369Sdim
657327952Sdimtemplate <typename D32, typename D64, bool Inline>
658327952Sdimbool
659327952Sdimlldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
660327952Sdim  MightHaveChildren() {
661321369Sdim  return true;
662321369Sdim}
663321369Sdim
664327952Sdimtemplate <typename D32, typename D64, bool Inline>
665321369Sdimlldb::ValueObjectSP
666327952Sdimlldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
667327952Sdim  GetChildAtIndex(size_t idx) {
668321369Sdim  if (idx >= CalculateNumChildren())
669321369Sdim    return lldb::ValueObjectSP();
670327952Sdim  lldb::addr_t object_at_idx;
671327952Sdim  if (Inline) {
672327952Sdim    object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size;
673327952Sdim    object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header
674327952Sdim    object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer
675327952Sdim  } else {
676327952Sdim    object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
677327952Sdim  }
678321369Sdim  object_at_idx += (idx * m_ptr_size);
679327952Sdim
680321369Sdim  ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
681321369Sdim  if (!process_sp)
682321369Sdim    return lldb::ValueObjectSP();
683321369Sdim  Status error;
684321369Sdim  if (error.Fail())
685321369Sdim    return lldb::ValueObjectSP();
686321369Sdim  StreamString idx_name;
687321369Sdim  idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
688321369Sdim  return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
689321369Sdim                                      m_exe_ctx_ref, m_id_type);
690321369Sdim}
691321369Sdim
692314564Sdimlldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
693314564Sdim    lldb::ValueObjectSP valobj_sp)
694314564Sdim    : SyntheticChildrenFrontEnd(*valobj_sp) {}
695292932Sdim
696292932Sdimsize_t
697314564Sdimlldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(
698353358Sdim    ConstString name) {
699314564Sdim  return UINT32_MAX;
700292932Sdim}
701292932Sdim
702292932Sdimsize_t
703314564Sdimlldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {
704314564Sdim  return 0;
705292932Sdim}
706292932Sdim
707314564Sdimbool lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {
708314564Sdim  return false;
709292932Sdim}
710292932Sdim
711314564Sdimbool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {
712314564Sdim  return false;
713292932Sdim}
714292932Sdim
715292932Sdimlldb::ValueObjectSP
716314564Sdimlldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(
717314564Sdim    size_t idx) {
718314564Sdim  return lldb::ValueObjectSP();
719292932Sdim}
720292932Sdim
721314564Sdimlldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(
722314564Sdim    lldb::ValueObjectSP valobj_sp)
723314564Sdim    : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}
724309124Sdim
725309124Sdimsize_t
726314564Sdimlldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(
727353358Sdim    ConstString name) {
728314564Sdim  static const ConstString g_zero("[0]");
729314564Sdim
730314564Sdim  if (name == g_zero)
731314564Sdim    return 0;
732314564Sdim
733314564Sdim  return UINT32_MAX;
734309124Sdim}
735309124Sdim
736309124Sdimsize_t
737314564Sdimlldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {
738314564Sdim  return 1;
739309124Sdim}
740309124Sdim
741314564Sdimbool lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {
742314564Sdim  return false;
743309124Sdim}
744309124Sdim
745314564Sdimbool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() {
746314564Sdim  return true;
747309124Sdim}
748309124Sdim
749309124Sdimlldb::ValueObjectSP
750314564Sdimlldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(
751314564Sdim    size_t idx) {
752314564Sdim  static const ConstString g_zero("[0]");
753314564Sdim
754314564Sdim  if (idx == 0) {
755360784Sdim    auto *clang_ast_context =
756360784Sdim        ClangASTContext::GetScratch(*m_backend.GetTargetSP());
757360784Sdim    if (clang_ast_context) {
758360784Sdim      CompilerType id_type(
759360784Sdim          clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID));
760360784Sdim      return m_backend.GetSyntheticChildAtOffset(
761360784Sdim          m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true,
762360784Sdim          g_zero);
763360784Sdim    }
764314564Sdim  }
765314564Sdim  return lldb::ValueObjectSP();
766309124Sdim}
767309124Sdim
768314564SdimSyntheticChildrenFrontEnd *
769314564Sdimlldb_private::formatters::NSArraySyntheticFrontEndCreator(
770314564Sdim    CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
771314564Sdim  if (!valobj_sp)
772314564Sdim    return nullptr;
773314564Sdim
774314564Sdim  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
775314564Sdim  if (!process_sp)
776314564Sdim    return nullptr;
777314564Sdim  AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
778353358Sdim      ObjCLanguageRuntime::Get(*process_sp));
779314564Sdim  if (!runtime)
780314564Sdim    return nullptr;
781314564Sdim
782314564Sdim  CompilerType valobj_type(valobj_sp->GetCompilerType());
783314564Sdim  Flags flags(valobj_type.GetTypeInfo());
784314564Sdim
785314564Sdim  if (flags.IsClear(eTypeIsPointer)) {
786321369Sdim    Status error;
787314564Sdim    valobj_sp = valobj_sp->AddressOf(error);
788314564Sdim    if (error.Fail() || !valobj_sp)
789314564Sdim      return nullptr;
790314564Sdim  }
791314564Sdim
792314564Sdim  ObjCLanguageRuntime::ClassDescriptorSP descriptor(
793314564Sdim      runtime->GetClassDescriptor(*valobj_sp));
794314564Sdim
795314564Sdim  if (!descriptor || !descriptor->IsValid())
796314564Sdim    return nullptr;
797314564Sdim
798314564Sdim  ConstString class_name(descriptor->GetClassName());
799314564Sdim
800314564Sdim  static const ConstString g_NSArrayI("__NSArrayI");
801327952Sdim  static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
802327952Sdim  static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
803314564Sdim  static const ConstString g_NSArrayM("__NSArrayM");
804314564Sdim  static const ConstString g_NSArray0("__NSArray0");
805314564Sdim  static const ConstString g_NSArray1("__NSSingleObjectArrayI");
806321369Sdim  static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
807321369Sdim  static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
808344779Sdim  static const ConstString g_NSCallStackArray("_NSCallStackArray");
809314564Sdim
810314564Sdim  if (class_name.IsEmpty())
811314564Sdim    return nullptr;
812314564Sdim
813314564Sdim  if (class_name == g_NSArrayI) {
814327952Sdim    if (runtime->GetFoundationVersion() >= 1436)
815327952Sdim      return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp));
816327952Sdim    if (runtime->GetFoundationVersion() >= 1430)
817327952Sdim      return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp));
818327952Sdim    else
819327952Sdim      return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));
820327952Sdim  } else if (class_name == g_NSArrayI_Transfer) {
821327952Sdim      return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));
822314564Sdim  } else if (class_name == g_NSArray0) {
823327952Sdim  } else if (class_name == g_NSFrozenArrayM) {
824327952Sdim    return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));
825327952Sdim  } else if (class_name == g_NSArray0) {
826314564Sdim    return (new NSArray0SyntheticFrontEnd(valobj_sp));
827314564Sdim  } else if (class_name == g_NSArray1) {
828314564Sdim    return (new NSArray1SyntheticFrontEnd(valobj_sp));
829314564Sdim  } else if (class_name == g_NSArrayM) {
830327952Sdim    if (runtime->GetFoundationVersion() >= 1437)
831327952Sdim      return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp));
832327952Sdim    if (runtime->GetFoundationVersion() >= 1428)
833327952Sdim      return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp));
834314564Sdim    if (runtime->GetFoundationVersion() >= 1100)
835327952Sdim      return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));
836344779Sdim  } else if (class_name == g_NSCallStackArray) {
837344779Sdim    return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp));
838314564Sdim  } else {
839314564Sdim    auto &map(NSArray_Additionals::GetAdditionalSynthetics());
840314564Sdim    auto iter = map.find(class_name), end = map.end();
841314564Sdim    if (iter != end)
842314564Sdim      return iter->second(synth, valobj_sp);
843314564Sdim  }
844314564Sdim
845314564Sdim  return nullptr;
846292932Sdim}
847