brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.7 KiB · 25376e0 Raw
856 lines · cpp
1//===-- NSArray.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 "clang/AST/ASTContext.h"10#include "clang/Basic/TargetInfo.h"11 12#include "Cocoa.h"13 14#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"15#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"16 17#include "lldb/DataFormatters/FormattersHelpers.h"18#include "lldb/Expression/FunctionCaller.h"19#include "lldb/Target/Language.h"20#include "lldb/Target/Target.h"21#include "lldb/Utility/DataBufferHeap.h"22#include "lldb/Utility/Endian.h"23#include "lldb/Utility/Status.h"24#include "lldb/Utility/Stream.h"25#include "lldb/ValueObject/ValueObject.h"26#include "lldb/ValueObject/ValueObjectConstResult.h"27 28using namespace lldb;29using namespace lldb_private;30using namespace lldb_private::formatters;31 32namespace lldb_private {33namespace formatters {34std::map<ConstString, CXXFunctionSummaryFormat::Callback> &35NSArray_Additionals::GetAdditionalSummaries() {36  static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;37  return g_map;38}39 40std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &41NSArray_Additionals::GetAdditionalSynthetics() {42  static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>43      g_map;44  return g_map;45}46 47class NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd {48public:49  NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp);50 51  ~NSArrayMSyntheticFrontEndBase() override = default;52 53  llvm::Expected<uint32_t> CalculateNumChildren() override;54 55  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;56 57  lldb::ChildCacheState Update() override = 0;58 59  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;60 61protected:62  virtual lldb::addr_t GetDataAddress() = 0;63 64  virtual uint64_t GetUsedCount() = 0;65 66  virtual uint64_t GetOffset() = 0;67 68  virtual uint64_t GetSize() = 0;69 70  ExecutionContextRef m_exe_ctx_ref;71  uint8_t m_ptr_size = 8;72  CompilerType m_id_type;73};74 75template <typename D32, typename D64>76class GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase {77public:78  GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);79 80  ~GenericNSArrayMSyntheticFrontEnd() override;81 82  lldb::ChildCacheState Update() override;83 84protected:85  lldb::addr_t GetDataAddress() override;86 87  uint64_t GetUsedCount() override;88 89  uint64_t GetOffset() override;90 91  uint64_t GetSize() override;92 93private:94  D32 *m_data_32;95  D64 *m_data_64;96};97 98namespace Foundation1010 {99  namespace {100    struct DataDescriptor_32 {101      uint32_t _used;102      uint32_t _offset;103      uint32_t _size : 28;104      uint64_t _priv1 : 4;105      uint32_t _priv2;106      uint32_t _data;107    };108 109    struct DataDescriptor_64 {110      uint64_t _used;111      uint64_t _offset;112      uint64_t _size : 60;113      uint64_t _priv1 : 4;114      uint32_t _priv2;115      uint64_t _data;116    };117  }118 119  using NSArrayMSyntheticFrontEnd =120      GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;121}122 123namespace Foundation1428 {124  namespace {125    struct DataDescriptor_32 {126      uint32_t _used;127      uint32_t _offset;128      uint32_t _size;129      uint32_t _data;130    };131 132    struct DataDescriptor_64 {133      uint64_t _used;134      uint64_t _offset;135      uint64_t _size;136      uint64_t _data;137    };138  }139 140  using NSArrayMSyntheticFrontEnd =141      GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;142}143 144namespace Foundation1437 {145  template <typename PtrType>146  struct DataDescriptor {147    PtrType _cow;148    // __deque149    PtrType _data;150    uint32_t _offset;151    uint32_t _size;152    uint32_t _muts;153    uint32_t _used;154  };155 156  using NSArrayMSyntheticFrontEnd =157     GenericNSArrayMSyntheticFrontEnd<158        DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>;159 160  template <typename DD>161  uint64_t162  __NSArrayMSize_Impl(lldb_private::Process &process,163                      lldb::addr_t valobj_addr, Status &error) {164    const lldb::addr_t start_of_descriptor =165    valobj_addr + process.GetAddressByteSize();166    DD descriptor = DD();167    process.ReadMemory(start_of_descriptor, &descriptor,168                       sizeof(descriptor), error);169    if (error.Fail()) {170      return 0;171    }172    return descriptor._used;173  }174 175  uint64_t176  __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,177                 Status &error) {178    if (process.GetAddressByteSize() == 4) {179      return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr,180                                                           error);181    } else {182      return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr,183                                                           error);184    }185  }186 187}188 189namespace CallStackArray {190struct DataDescriptor_32 {191  uint32_t _data;192  uint32_t _used;193  uint32_t _offset;194  const uint32_t _size = 0;195};196 197struct DataDescriptor_64 {198  uint64_t _data;199  uint64_t _used;200  uint64_t _offset;201  const uint64_t _size = 0;202};203 204using NSCallStackArraySyntheticFrontEnd =205    GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;206} // namespace CallStackArray207 208template <typename D32, typename D64, bool Inline>209class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {210public:211  GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);212 213  ~GenericNSArrayISyntheticFrontEnd() override;214 215  llvm::Expected<uint32_t> CalculateNumChildren() override;216 217  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;218 219  lldb::ChildCacheState Update() override;220 221  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;222 223private:224  ExecutionContextRef m_exe_ctx_ref;225  uint8_t m_ptr_size = 8;226 227  D32 *m_data_32;228  D64 *m_data_64;229  CompilerType m_id_type;230};231 232namespace Foundation1300 {233    struct IDD32 {234        uint32_t used;235        uint32_t list;236    };237 238    struct IDD64 {239        uint64_t used;240        uint64_t list;241    };242 243    using NSArrayISyntheticFrontEnd =244        GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;245}246 247namespace Foundation1430 {248    using NSArrayISyntheticFrontEnd =249        Foundation1428::NSArrayMSyntheticFrontEnd;250}251 252namespace Foundation1436 {253    struct IDD32 {254        uint32_t used;255        uint32_t list; // in Inline cases, this is the first element256    };257 258    struct IDD64 {259        uint64_t used;260        uint64_t list; // in Inline cases, this is the first element261    };262 263    using NSArrayI_TransferSyntheticFrontEnd =264        GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>;265 266    using NSArrayISyntheticFrontEnd =267        GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;268 269    using NSFrozenArrayMSyntheticFrontEnd =270        Foundation1437::NSArrayMSyntheticFrontEnd;271 272    uint64_t273    __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,274                         Status &error) {275      return Foundation1437::__NSArrayMSize(process, valobj_addr, error);276    }277}278 279namespace ConstantArray {280 281struct ConstantArray32 {282  uint64_t used;283  uint32_t list;284};285 286struct ConstantArray64 {287  uint64_t used;288  uint64_t list;289};290 291using NSConstantArraySyntheticFrontEnd =292    GenericNSArrayISyntheticFrontEnd<ConstantArray32, ConstantArray64, false>;293} // namespace ConstantArray294 295class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {296public:297  NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);298 299  ~NSArray0SyntheticFrontEnd() override = default;300 301  llvm::Expected<uint32_t> CalculateNumChildren() override;302 303  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;304 305  lldb::ChildCacheState Update() override;306 307  bool MightHaveChildren() override;308 309  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;310};311 312class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {313public:314  NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);315 316  ~NSArray1SyntheticFrontEnd() override = default;317 318  llvm::Expected<uint32_t> CalculateNumChildren() override;319 320  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;321 322  lldb::ChildCacheState Update() override;323 324  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;325};326} // namespace formatters327} // namespace lldb_private328 329bool lldb_private::formatters::NSArraySummaryProvider(330    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {331  static constexpr llvm::StringLiteral g_TypeHint("NSArray");332 333  ProcessSP process_sp = valobj.GetProcessSP();334  if (!process_sp)335    return false;336 337  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);338 339  if (!runtime)340    return false;341 342  ObjCLanguageRuntime::ClassDescriptorSP descriptor(343      runtime->GetClassDescriptor(valobj));344 345  if (!descriptor || !descriptor->IsValid())346    return false;347 348  uint32_t ptr_size = process_sp->GetAddressByteSize();349 350  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);351 352  if (!valobj_addr)353    return false;354 355  uint64_t value = 0;356 357  ConstString class_name(descriptor->GetClassName());358 359  static const ConstString g_NSArrayI("__NSArrayI");360  static const ConstString g_NSArrayM("__NSArrayM");361  static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");362  static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");363  static const ConstString g_NSArray0("__NSArray0");364  static const ConstString g_NSArray1("__NSSingleObjectArrayI");365  static const ConstString g_NSArrayCF("__NSCFArray");366  static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");367  static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");368  static const ConstString g_NSCallStackArray("_NSCallStackArray");369  static const ConstString g_NSConstantArray("NSConstantArray");370 371  if (class_name.IsEmpty())372    return false;373 374  if (class_name == g_NSArrayI) {375    Status error;376    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,377                                                      ptr_size, 0, error);378    if (error.Fail())379      return false;380  } else if (class_name == g_NSConstantArray) {381    Status error;382    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 8,383                                                      0, error);384    if (error.Fail())385      return false;386  } else if (class_name == g_NSArrayM) {387    AppleObjCRuntime *apple_runtime =388    llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);389    Status error;390    if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {391      value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error);392    } else {393      value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,394                                                        ptr_size, 0, error);395    }396    if (error.Fail())397      return false;398  } else if (class_name == g_NSArrayI_Transfer) {399    Status error;400    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,401                                                      ptr_size, 0, error);402    if (error.Fail())403      return false;404  } else if (class_name == g_NSFrozenArrayM) {405    Status error;406    value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error);407    if (error.Fail())408      return false;409  } else if (class_name == g_NSArrayMLegacy) {410    Status error;411    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,412                                                      ptr_size, 0, error);413    if (error.Fail())414      return false;415  } else if (class_name == g_NSArrayMImmutable) {416    Status error;417    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,418                                                      ptr_size, 0, error);419    if (error.Fail())420      return false;421  } else if (class_name == g_NSArray0) {422    value = 0;423  } else if (class_name == g_NSArray1) {424    value = 1;425  } else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) {426    // __NSCFArray and _NSCallStackArray store the number of elements as a427    // pointer-sized value at offset `2 * ptr_size`.428    Status error;429    value = process_sp->ReadUnsignedIntegerFromMemory(430        valobj_addr + 2 * ptr_size, ptr_size, 0, error);431    if (error.Fail())432      return false;433  } else {434    auto &map(NSArray_Additionals::GetAdditionalSummaries());435    auto iter = map.find(class_name), end = map.end();436    if (iter != end)437      return iter->second(valobj, stream, options);438    else439      return false;440  }441 442  llvm::StringRef prefix, suffix;443  if (Language *language = Language::FindPlugin(options.GetLanguage()))444    std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);445 446  stream << prefix;447  stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");448  stream << suffix;449  return true;450}451 452lldb_private::formatters::NSArrayMSyntheticFrontEndBase::453    NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp)454    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_id_type() {455  if (valobj_sp) {456    TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(457        *valobj_sp->GetExecutionContextRef().GetTargetSP());458    if (scratch_ts_sp)459      m_id_type = CompilerType(460          scratch_ts_sp->weak_from_this(),461          scratch_ts_sp->getASTContext().ObjCBuiltinIdTy.getAsOpaquePtr());462    if (valobj_sp->GetProcessSP())463      m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();464  }465}466 467template <typename D32, typename D64>468lldb_private::formatters::469  GenericNSArrayMSyntheticFrontEnd<D32, D64>::470    GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)471    : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr),472      m_data_64(nullptr) {}473 474llvm::Expected<uint32_t> lldb_private::formatters::475    NSArrayMSyntheticFrontEndBase::CalculateNumChildren() {476  return GetUsedCount();477}478 479lldb::ValueObjectSP480lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(481    uint32_t idx) {482  if (idx >= CalculateNumChildrenIgnoringErrors())483    return lldb::ValueObjectSP();484  lldb::addr_t object_at_idx = GetDataAddress();485  size_t pyhs_idx = idx;486  pyhs_idx += GetOffset();487  if (GetSize() <= pyhs_idx)488    pyhs_idx -= GetSize();489  object_at_idx += (pyhs_idx * m_ptr_size);490  StreamString idx_name;491  idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);492  return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,493                                      m_exe_ctx_ref, m_id_type);494}495 496template <typename D32, typename D64>497lldb::ChildCacheState498lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {499  ValueObjectSP valobj_sp = m_backend.GetSP();500  m_ptr_size = 0;501  delete m_data_32;502  m_data_32 = nullptr;503  delete m_data_64;504  m_data_64 = nullptr;505  if (!valobj_sp)506    return lldb::ChildCacheState::eRefetch;507  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();508  Status error;509  error.Clear();510  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());511  if (!process_sp)512    return lldb::ChildCacheState::eRefetch;513  m_ptr_size = process_sp->GetAddressByteSize();514  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;515  if (m_ptr_size == 4) {516    m_data_32 = new D32();517    process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),518                           error);519  } else {520    m_data_64 = new D64();521    process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),522                           error);523  }524 525  return error.Success() ? lldb::ChildCacheState::eReuse526                         : lldb::ChildCacheState::eRefetch;527}528 529llvm::Expected<size_t> lldb_private::formatters::NSArrayMSyntheticFrontEndBase::530    GetIndexOfChildWithName(ConstString name) {531  auto optional_idx = ExtractIndexFromString(name.AsCString());532  if (!optional_idx) {533    return llvm::createStringError("Type has no child named '%s'",534                                   name.AsCString());535  }536  uint32_t idx = *optional_idx;537  if (idx >= CalculateNumChildrenIgnoringErrors())538    return llvm::createStringError("Type has no child named '%s'",539                                   name.AsCString());540  return idx;541}542 543template <typename D32, typename D64>544lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::545    GenericNSArrayMSyntheticFrontEnd::~GenericNSArrayMSyntheticFrontEnd() {546  delete m_data_32;547  m_data_32 = nullptr;548  delete m_data_64;549  m_data_64 = nullptr;550}551 552template <typename D32, typename D64>553lldb::addr_t554lldb_private::formatters::555  GenericNSArrayMSyntheticFrontEnd<D32, D64>::556    GenericNSArrayMSyntheticFrontEnd::GetDataAddress() {557  if (!m_data_32 && !m_data_64)558    return LLDB_INVALID_ADDRESS;559  return m_data_32 ? m_data_32->_data : m_data_64->_data;560}561 562template <typename D32, typename D64>563uint64_t564lldb_private::formatters::565  GenericNSArrayMSyntheticFrontEnd<D32, D64>::566    GenericNSArrayMSyntheticFrontEnd::GetUsedCount() {567  if (!m_data_32 && !m_data_64)568    return 0;569  return m_data_32 ? m_data_32->_used : m_data_64->_used;570}571 572template <typename D32, typename D64>573uint64_t574lldb_private::formatters::575  GenericNSArrayMSyntheticFrontEnd<D32, D64>::576    GenericNSArrayMSyntheticFrontEnd::GetOffset() {577  if (!m_data_32 && !m_data_64)578    return 0;579  return m_data_32 ? m_data_32->_offset : m_data_64->_offset;580}581 582template <typename D32, typename D64>583uint64_t584lldb_private::formatters::585  GenericNSArrayMSyntheticFrontEnd<D32, D64>::586    GenericNSArrayMSyntheticFrontEnd::GetSize() {587  if (!m_data_32 && !m_data_64)588    return 0;589  return m_data_32 ? m_data_32->_size : m_data_64->_size;590}591 592template <typename D32, typename D64, bool Inline>593lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::594    GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)595    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),596      m_data_32(nullptr), m_data_64(nullptr) {597  if (valobj_sp) {598    CompilerType type = valobj_sp->GetCompilerType();599    if (type) {600      TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(601          *valobj_sp->GetExecutionContextRef().GetTargetSP());602      if (scratch_ts_sp)603        m_id_type = scratch_ts_sp->GetType(604            scratch_ts_sp->getASTContext().ObjCBuiltinIdTy);605    }606  }607}608 609template <typename D32, typename D64, bool Inline>610lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::611    GenericNSArrayISyntheticFrontEnd::~GenericNSArrayISyntheticFrontEnd() {612  delete m_data_32;613  m_data_32 = nullptr;614  delete m_data_64;615  m_data_64 = nullptr;616}617 618template <typename D32, typename D64, bool Inline>619llvm::Expected<size_t>620lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<621    D32, D64, Inline>::GetIndexOfChildWithName(ConstString name) {622  auto optional_idx = ExtractIndexFromString(name.AsCString());623  if (!optional_idx) {624    return llvm::createStringError("Type has no child named '%s'",625                                   name.AsCString());626  }627  uint32_t idx = *optional_idx;628  if (idx >= CalculateNumChildrenIgnoringErrors())629    return llvm::createStringError("Type has no child named '%s'",630                                   name.AsCString());631  return idx;632}633 634template <typename D32, typename D64, bool Inline>635llvm::Expected<uint32_t>636lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<637    D32, D64, Inline>::CalculateNumChildren() {638  return m_data_32 ? m_data_32->used : m_data_64->used;639}640 641template <typename D32, typename D64, bool Inline>642lldb::ChildCacheState643lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64,644                                                           Inline>::Update() {645  ValueObjectSP valobj_sp = m_backend.GetSP();646  m_ptr_size = 0;647  delete m_data_32;648  m_data_32 = nullptr;649  delete m_data_64;650  m_data_64 = nullptr;651  if (!valobj_sp)652    return lldb::ChildCacheState::eRefetch;653  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();654  Status error;655  error.Clear();656  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());657  if (!process_sp)658    return lldb::ChildCacheState::eRefetch;659  m_ptr_size = process_sp->GetAddressByteSize();660  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;661  if (m_ptr_size == 4) {662    m_data_32 = new D32();663    process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),664                           error);665  } else {666    m_data_64 = new D64();667    process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),668                           error);669  }670 671  return error.Success() ? lldb::ChildCacheState::eReuse672                         : lldb::ChildCacheState::eRefetch;673}674 675template <typename D32, typename D64, bool Inline>676lldb::ValueObjectSP677lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::678  GetChildAtIndex(uint32_t idx) {679  if (idx >= CalculateNumChildrenIgnoringErrors())680    return lldb::ValueObjectSP();681  lldb::addr_t object_at_idx;682  if (Inline) {683    object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size;684    object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header685    object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer686  } else {687    object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;688  }689  object_at_idx += (idx * m_ptr_size);690 691  ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();692  if (!process_sp)693    return lldb::ValueObjectSP();694  Status error;695  if (error.Fail())696    return lldb::ValueObjectSP();697  StreamString idx_name;698  idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);699  return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,700                                      m_exe_ctx_ref, m_id_type);701}702 703lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(704    lldb::ValueObjectSP valobj_sp)705    : SyntheticChildrenFrontEnd(*valobj_sp) {}706 707llvm::Expected<size_t>708lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(709    ConstString name) {710  return UINT32_MAX;711}712 713llvm::Expected<uint32_t>714lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {715  return 0;716}717 718lldb::ChildCacheState719lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {720  return lldb::ChildCacheState::eRefetch;721}722 723bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {724  return false;725}726 727lldb::ValueObjectSP728lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(729    uint32_t idx) {730  return lldb::ValueObjectSP();731}732 733lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(734    lldb::ValueObjectSP valobj_sp)735    : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}736 737llvm::Expected<size_t>738lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(739    ConstString name) {740  static const ConstString g_zero("[0]");741 742  if (name == g_zero)743    return 0;744 745  return UINT32_MAX;746}747 748llvm::Expected<uint32_t>749lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {750  return 1;751}752 753lldb::ChildCacheState754lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {755  return lldb::ChildCacheState::eRefetch;756}757 758lldb::ValueObjectSP759lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(760    uint32_t idx) {761  static const ConstString g_zero("[0]");762 763  if (idx == 0) {764    TypeSystemClangSP scratch_ts_sp =765        ScratchTypeSystemClang::GetForTarget(*m_backend.GetTargetSP());766    if (scratch_ts_sp) {767      CompilerType id_type(scratch_ts_sp->GetBasicType(lldb::eBasicTypeObjCID));768      return m_backend.GetSyntheticChildAtOffset(769          m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true,770          g_zero);771    }772  }773  return lldb::ValueObjectSP();774}775 776SyntheticChildrenFrontEnd *777lldb_private::formatters::NSArraySyntheticFrontEndCreator(778    CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {779  if (!valobj_sp)780    return nullptr;781 782  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());783  if (!process_sp)784    return nullptr;785  AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(786      ObjCLanguageRuntime::Get(*process_sp));787  if (!runtime)788    return nullptr;789 790  CompilerType valobj_type(valobj_sp->GetCompilerType());791  Flags flags(valobj_type.GetTypeInfo());792 793  if (flags.IsClear(eTypeIsPointer)) {794    Status error;795    valobj_sp = valobj_sp->AddressOf(error);796    if (error.Fail() || !valobj_sp)797      return nullptr;798  }799 800  ObjCLanguageRuntime::ClassDescriptorSP descriptor(801      runtime->GetClassDescriptor(*valobj_sp));802 803  if (!descriptor || !descriptor->IsValid())804    return nullptr;805 806  ConstString class_name(descriptor->GetClassName());807 808  static const ConstString g_NSArrayI("__NSArrayI");809  static const ConstString g_NSConstantArray("NSConstantArray");810  static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");811  static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");812  static const ConstString g_NSArrayM("__NSArrayM");813  static const ConstString g_NSArray0("__NSArray0");814  static const ConstString g_NSArray1("__NSSingleObjectArrayI");815  static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");816  static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");817  static const ConstString g_NSCallStackArray("_NSCallStackArray");818 819  if (class_name.IsEmpty())820    return nullptr;821 822  if (class_name == g_NSArrayI) {823    if (runtime->GetFoundationVersion() >= 1436)824      return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp));825    if (runtime->GetFoundationVersion() >= 1430)826      return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp));827    return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));828  } else if (class_name == g_NSArrayI_Transfer) {829      return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));830  } else if (class_name == g_NSConstantArray) {831    return new ConstantArray::NSConstantArraySyntheticFrontEnd(valobj_sp);832  } else if (class_name == g_NSFrozenArrayM) {833    return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));834  } else if (class_name == g_NSArray0) {835    return (new NSArray0SyntheticFrontEnd(valobj_sp));836  } else if (class_name == g_NSArray1) {837    return (new NSArray1SyntheticFrontEnd(valobj_sp));838  } else if (class_name == g_NSArrayM) {839    if (runtime->GetFoundationVersion() >= 1437)840      return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp));841    if (runtime->GetFoundationVersion() >= 1428)842      return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp));843    if (runtime->GetFoundationVersion() >= 1100)844      return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));845  } else if (class_name == g_NSCallStackArray) {846    return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp));847  } else {848    auto &map(NSArray_Additionals::GetAdditionalSynthetics());849    auto iter = map.find(class_name), end = map.end();850    if (iter != end)851      return iter->second(synth, valobj_sp);852  }853 854  return nullptr;855}856