brintos

brintos / llvm-project-archived public Read only

0
0
Text · 44.5 KiB · 24e8489 Raw
1374 lines · cpp
1//===-- NSDictionary.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 <mutex>10 11#include "clang/AST/DeclCXX.h"12 13#include "CFBasicHash.h"14#include "NSDictionary.h"15 16#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"17#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"18 19#include "lldb/DataFormatters/FormattersHelpers.h"20#include "lldb/Target/Language.h"21#include "lldb/Target/StackFrame.h"22#include "lldb/Target/Target.h"23#include "lldb/Utility/DataBufferHeap.h"24#include "lldb/Utility/Endian.h"25#include "lldb/Utility/Status.h"26#include "lldb/Utility/Stream.h"27#include "lldb/ValueObject/ValueObject.h"28#include "lldb/ValueObject/ValueObjectConstResult.h"29 30using namespace lldb;31using namespace lldb_private;32using namespace lldb_private::formatters;33 34NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(35    ConstString p)36    : m_prefix(p) {}37 38bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(39    ConstString class_name) {40  return class_name.GetStringRef().starts_with(m_prefix.GetStringRef());41}42 43NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)44    : m_name(n) {}45 46bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match(47    ConstString class_name) {48  return (class_name == m_name);49}50 51NSDictionary_Additionals::AdditionalFormatters<52    CXXFunctionSummaryFormat::Callback> &53NSDictionary_Additionals::GetAdditionalSummaries() {54  static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map;55  return g_map;56}57 58NSDictionary_Additionals::AdditionalFormatters<59    CXXSyntheticChildren::CreateFrontEndCallback> &60NSDictionary_Additionals::GetAdditionalSynthetics() {61  static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback>62      g_map;63  return g_map;64}65 66static CompilerType GetLLDBNSPairType(TargetSP target_sp) {67  CompilerType compiler_type;68  TypeSystemClangSP scratch_ts_sp =69      ScratchTypeSystemClang::GetForTarget(*target_sp);70 71  if (!scratch_ts_sp)72    return compiler_type;73 74  static constexpr llvm::StringLiteral g_lldb_autogen_nspair("__lldb_autogen_nspair");75 76  compiler_type = scratch_ts_sp->GetTypeForIdentifier<clang::CXXRecordDecl>(77      scratch_ts_sp->getASTContext(), g_lldb_autogen_nspair);78 79  if (!compiler_type) {80    compiler_type = scratch_ts_sp->CreateRecordType(81        nullptr, OptionalClangModuleID(), lldb::eAccessPublic,82        g_lldb_autogen_nspair, llvm::to_underlying(clang::TagTypeKind::Struct),83        lldb::eLanguageTypeC);84 85    if (compiler_type) {86      TypeSystemClang::StartTagDeclarationDefinition(compiler_type);87      CompilerType id_compiler_type =88          scratch_ts_sp->GetBasicType(eBasicTypeObjCID);89      TypeSystemClang::AddFieldToRecordType(90          compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);91      TypeSystemClang::AddFieldToRecordType(92          compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);93      TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);94    }95  }96  return compiler_type;97}98 99namespace lldb_private {100namespace formatters {101class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd {102public:103  NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);104 105  ~NSDictionaryISyntheticFrontEnd() override;106 107  llvm::Expected<uint32_t> CalculateNumChildren() override;108 109  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;110 111  lldb::ChildCacheState Update() override;112 113  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;114 115private:116  struct DataDescriptor_32 {117    uint32_t _used : 26;118    uint32_t _szidx : 6;119  };120 121  struct DataDescriptor_64 {122    uint64_t _used : 58;123    uint32_t _szidx : 6;124  };125 126  struct DictionaryItemDescriptor {127    lldb::addr_t key_ptr;128    lldb::addr_t val_ptr;129    lldb::ValueObjectSP valobj_sp;130  };131 132  ExecutionContextRef m_exe_ctx_ref;133  uint8_t m_ptr_size = 8;134  lldb::ByteOrder m_order = lldb::eByteOrderInvalid;135  DataDescriptor_32 *m_data_32 = nullptr;136  DataDescriptor_64 *m_data_64 = nullptr;137  lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;138  CompilerType m_pair_type;139  std::vector<DictionaryItemDescriptor> m_children;140};141 142class NSConstantDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {143public:144  NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);145 146  llvm::Expected<uint32_t> CalculateNumChildren() override;147 148  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;149 150  lldb::ChildCacheState Update() override;151 152  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;153 154private:155  ExecutionContextRef m_exe_ctx_ref;156  CompilerType m_pair_type;157  uint8_t m_ptr_size = 8;158  lldb::ByteOrder m_order = lldb::eByteOrderInvalid;159  unsigned int m_size = 0;160  lldb::addr_t m_keys_ptr = LLDB_INVALID_ADDRESS;161  lldb::addr_t m_objects_ptr = LLDB_INVALID_ADDRESS;162 163  struct DictionaryItemDescriptor {164    lldb::addr_t key_ptr;165    lldb::addr_t val_ptr;166    lldb::ValueObjectSP valobj_sp;167  };168 169  std::vector<DictionaryItemDescriptor> m_children;170};171 172class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {173public:174  NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);175 176  llvm::Expected<uint32_t> CalculateNumChildren() override;177 178  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;179 180  lldb::ChildCacheState Update() override;181 182  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;183 184private:185  struct DictionaryItemDescriptor {186    lldb::addr_t key_ptr;187    lldb::addr_t val_ptr;188    lldb::ValueObjectSP valobj_sp;189  };190 191  ExecutionContextRef m_exe_ctx_ref;192  uint8_t m_ptr_size = 8;193  lldb::ByteOrder m_order = lldb::eByteOrderInvalid;194 195  CFBasicHash m_hashtable;196 197  CompilerType m_pair_type;198  std::vector<DictionaryItemDescriptor> m_children;199};200 201class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {202public:203  NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);204 205  ~NSDictionary1SyntheticFrontEnd() override = default;206 207  llvm::Expected<uint32_t> CalculateNumChildren() override;208 209  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;210 211  lldb::ChildCacheState Update() override;212 213  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;214 215private:216  ValueObjectSP m_pair;217};218 219template <typename D32, typename D64>220class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {221public:222  GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);223 224  ~GenericNSDictionaryMSyntheticFrontEnd() override;225 226  llvm::Expected<uint32_t> CalculateNumChildren() override;227 228  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;229 230  lldb::ChildCacheState Update() override;231 232  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;233 234private:235  struct DictionaryItemDescriptor {236    lldb::addr_t key_ptr;237    lldb::addr_t val_ptr;238    lldb::ValueObjectSP valobj_sp;239  };240 241  ExecutionContextRef m_exe_ctx_ref;242  uint8_t m_ptr_size = 8;243  lldb::ByteOrder m_order = lldb::eByteOrderInvalid;244  D32 *m_data_32;245  D64 *m_data_64;246  CompilerType m_pair_type;247  std::vector<DictionaryItemDescriptor> m_children;248};249  250namespace Foundation1100 {251  class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {252  public:253    NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);254    255    ~NSDictionaryMSyntheticFrontEnd() override;256 257    llvm::Expected<uint32_t> CalculateNumChildren() override;258 259    lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;260 261    lldb::ChildCacheState Update() override;262 263    llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;264 265  private:266    struct DataDescriptor_32 {267      uint32_t _used : 26;268      uint32_t _kvo : 1;269      uint32_t _size;270      uint32_t _mutations;271      uint32_t _objs_addr;272      uint32_t _keys_addr;273    };274    275    struct DataDescriptor_64 {276      uint64_t _used : 58;277      uint32_t _kvo : 1;278      uint64_t _size;279      uint64_t _mutations;280      uint64_t _objs_addr;281      uint64_t _keys_addr;282    };283    284    struct DictionaryItemDescriptor {285      lldb::addr_t key_ptr;286      lldb::addr_t val_ptr;287      lldb::ValueObjectSP valobj_sp;288    };289    290    ExecutionContextRef m_exe_ctx_ref;291    uint8_t m_ptr_size = 8;292    lldb::ByteOrder m_order = lldb::eByteOrderInvalid;293    DataDescriptor_32 *m_data_32 = nullptr;294    DataDescriptor_64 *m_data_64 = nullptr;295    CompilerType m_pair_type;296    std::vector<DictionaryItemDescriptor> m_children;297  };298}299  300namespace Foundation1428 {301  namespace {302    struct DataDescriptor_32 {303      uint32_t _used : 26;304      uint32_t _kvo : 1;305      uint32_t _size;306      uint32_t _buffer;307      uint64_t GetSize() { return _size; }308    };309    310    struct DataDescriptor_64 {311      uint64_t _used : 58;312      uint32_t _kvo : 1;313      uint64_t _size;314      uint64_t _buffer;315      uint64_t GetSize() { return _size; }316    };317  }318 319  using NSDictionaryMSyntheticFrontEnd =320    GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;321}322  323namespace Foundation1437 {324    static const uint64_t NSDictionaryCapacities[] = {325        0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,326        2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,327        214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,328        6221311, 10066421, 16287743, 26354171, 42641881, 68996069,329        111638519, 180634607, 292272623, 472907251330    };331    332    static const size_t NSDictionaryNumSizeBuckets =333        sizeof(NSDictionaryCapacities) / sizeof(uint64_t);334 335    namespace {336    struct DataDescriptor_32 {337      uint32_t _buffer;338      uint32_t _muts;339      uint32_t _used : 25;340      uint32_t _kvo : 1;341      uint32_t _szidx : 6;342 343      uint64_t GetSize() {344        return (_szidx) >= NSDictionaryNumSizeBuckets ?345            0 : NSDictionaryCapacities[_szidx];346      }347    };348    349    struct DataDescriptor_64 {350      uint64_t _buffer;351      uint32_t _muts;352      uint32_t _used : 25;353      uint32_t _kvo : 1;354      uint32_t _szidx : 6;355 356      uint64_t GetSize() {357        return (_szidx) >= NSDictionaryNumSizeBuckets ?358            0 : NSDictionaryCapacities[_szidx];359      }360    };361    } // namespace362 363  using NSDictionaryMSyntheticFrontEnd =364    GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;365  366  template <typename DD>367  uint64_t368  __NSDictionaryMSize_Impl(lldb_private::Process &process,369                           lldb::addr_t valobj_addr, Status &error) {370    const lldb::addr_t start_of_descriptor =371        valobj_addr + process.GetAddressByteSize();372    DD descriptor = DD();373    process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),374                       error);375    if (error.Fail()) {376      return 0;377    }378    return descriptor._used;379  }380  381  uint64_t382  __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,383               Status &error) {384    if (process.GetAddressByteSize() == 4) {385      return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,386                                                         error);387    } else {388      return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,389                                                         error);390    }391  }392 393}394} // namespace formatters395} // namespace lldb_private396 397template <bool name_entries>398bool lldb_private::formatters::NSDictionarySummaryProvider(399    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {400  static constexpr llvm::StringLiteral g_TypeHint("NSDictionary");401  ProcessSP process_sp = valobj.GetProcessSP();402  if (!process_sp)403    return false;404 405  ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);406 407  if (!runtime)408    return false;409 410  ObjCLanguageRuntime::ClassDescriptorSP descriptor(411      runtime->GetNonKVOClassDescriptor(valobj));412 413  if (!descriptor || !descriptor->IsValid())414    return false;415 416  uint32_t ptr_size = process_sp->GetAddressByteSize();417  bool is_64bit = (ptr_size == 8);418 419  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);420 421  if (!valobj_addr)422    return false;423 424  uint64_t value = 0;425 426  ConstString class_name(descriptor->GetClassName());427 428  static const ConstString g_DictionaryI("__NSDictionaryI");429  static const ConstString g_DictionaryM("__NSDictionaryM");430  static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");431  static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");432  static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");433  static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");434  static const ConstString g_Dictionary0("__NSDictionary0");435  static const ConstString g_DictionaryCF("__CFDictionary");436  static const ConstString g_DictionaryNSCF("__NSCFDictionary");437  static const ConstString g_DictionaryCFRef("CFDictionaryRef");438  static const ConstString g_ConstantDictionary("NSConstantDictionary");439 440  if (class_name.IsEmpty())441    return false;442 443  if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {444    Status error;445    value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,446                                                      ptr_size, 0, error);447    if (error.Fail())448      return false;449 450    value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);451  } else if (class_name == g_ConstantDictionary) {452    Status error;453    value = process_sp->ReadUnsignedIntegerFromMemory(454        valobj_addr + 2 * ptr_size, ptr_size, 0, error);455    if (error.Fail())456      return false;457  } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||458             class_name == g_DictionaryMFrozen) {459    AppleObjCRuntime *apple_runtime =460    llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);461    Status error;462    if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {463      value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,464                                                  error);465    } else {466      value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,467                                                        ptr_size, 0, error);468      value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);469    }470    if (error.Fail())471      return false;472  } else if (class_name == g_Dictionary1) {473    value = 1;474  } else if (class_name == g_Dictionary0) {475    value = 0;476  } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||477             class_name == g_DictionaryCFRef) {478    ExecutionContext exe_ctx(process_sp);479    CFBasicHash cfbh;480    if (!cfbh.Update(valobj_addr, exe_ctx))481      return false;482    value = cfbh.GetCount();483  } else {484    auto &map(NSDictionary_Additionals::GetAdditionalSummaries());485    for (auto &candidate : map) {486      if (candidate.first && candidate.first->Match(class_name))487        return candidate.second(valobj, stream, options);488    }489    return false;490  }491 492  llvm::StringRef prefix, suffix;493  if (Language *language = Language::FindPlugin(options.GetLanguage()))494    std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);495 496  stream << prefix;497  stream.Printf("%" PRIu64 " %s%s", value, "key/value pair",498                value == 1 ? "" : "s");499  stream << suffix;500  return true;501}502 503SyntheticChildrenFrontEnd *504lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(505    CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {506  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());507  if (!process_sp)508    return nullptr;509  AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(510      ObjCLanguageRuntime::Get(*process_sp));511  if (!runtime)512    return nullptr;513 514  CompilerType valobj_type(valobj_sp->GetCompilerType());515  Flags flags(valobj_type.GetTypeInfo());516 517  if (flags.IsClear(eTypeIsPointer)) {518    Status error;519    valobj_sp = valobj_sp->AddressOf(error);520    if (error.Fail() || !valobj_sp)521      return nullptr;522  }523 524  ObjCLanguageRuntime::ClassDescriptorSP descriptor(525      runtime->GetClassDescriptor(*valobj_sp));526 527  if (!descriptor || !descriptor->IsValid())528    return nullptr;529 530  ConstString class_name(descriptor->GetClassName());531 532  static const ConstString g_DictionaryI("__NSDictionaryI");533  static const ConstString g_DictionaryM("__NSDictionaryM");534  static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");535  static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");536  static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");537  static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");538  static const ConstString g_Dictionary0("__NSDictionary0");539  static const ConstString g_DictionaryCF("__CFDictionary");540  static const ConstString g_DictionaryNSCF("__NSCFDictionary");541  static const ConstString g_DictionaryCFRef("CFDictionaryRef");542  static const ConstString g_ConstantDictionary("NSConstantDictionary");543 544  if (class_name.IsEmpty())545    return nullptr;546 547  if (class_name == g_DictionaryI) {548    return (new NSDictionaryISyntheticFrontEnd(valobj_sp));549  } else if (class_name == g_ConstantDictionary) {550    return (new NSConstantDictionarySyntheticFrontEnd(valobj_sp));551  } else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) {552    if (runtime->GetFoundationVersion() >= 1437) {553      return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));554    } else if (runtime->GetFoundationVersion() >= 1428) {555      return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));556    } else {557      return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));558    }559  } else if (class_name == g_DictionaryMLegacy) {560    return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));561  } else if (class_name == g_Dictionary1) {562    return (new NSDictionary1SyntheticFrontEnd(valobj_sp));563  } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||564             class_name == g_DictionaryCFRef) {565    return (new NSCFDictionarySyntheticFrontEnd(valobj_sp));566  } else {567    auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());568    for (auto &candidate : map) {569      if (candidate.first && candidate.first->Match((class_name)))570        return candidate.second(synth, valobj_sp);571    }572  }573 574  return nullptr;575}576 577lldb_private::formatters::NSDictionaryISyntheticFrontEnd::578    NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)579    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}580 581lldb_private::formatters::NSDictionaryISyntheticFrontEnd::582    ~NSDictionaryISyntheticFrontEnd() {583  delete m_data_32;584  m_data_32 = nullptr;585  delete m_data_64;586  m_data_64 = nullptr;587}588 589llvm::Expected<size_t> lldb_private::formatters::590    NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {591  auto optional_idx = ExtractIndexFromString(name.AsCString());592  if (!optional_idx) {593    return llvm::createStringError("Type has no child named '%s'",594                                   name.AsCString());595  }596  uint32_t idx = *optional_idx;597  if (idx >= CalculateNumChildrenIgnoringErrors())598    return llvm::createStringError("Type has no child named '%s'",599                                   name.AsCString());600  return idx;601}602 603llvm::Expected<uint32_t> lldb_private::formatters::604    NSDictionaryISyntheticFrontEnd::CalculateNumChildren() {605  if (!m_data_32 && !m_data_64)606    return 0;607  return (m_data_32 ? m_data_32->_used : m_data_64->_used);608}609 610lldb::ChildCacheState611lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {612  m_children.clear();613  delete m_data_32;614  m_data_32 = nullptr;615  delete m_data_64;616  m_data_64 = nullptr;617  m_ptr_size = 0;618  ValueObjectSP valobj_sp = m_backend.GetSP();619  if (!valobj_sp)620    return lldb::ChildCacheState::eRefetch;621  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();622  Status error;623  error.Clear();624  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());625  if (!process_sp)626    return lldb::ChildCacheState::eRefetch;627  m_ptr_size = process_sp->GetAddressByteSize();628  m_order = process_sp->GetByteOrder();629  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;630  if (m_ptr_size == 4) {631    m_data_32 = new DataDescriptor_32();632    process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),633                           error);634  } else {635    m_data_64 = new DataDescriptor_64();636    process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),637                           error);638  }639  if (error.Fail())640    return lldb::ChildCacheState::eRefetch;641  m_data_ptr = data_location + m_ptr_size;642  return lldb::ChildCacheState::eRefetch;643}644 645lldb::ValueObjectSP646lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(647    uint32_t idx) {648  uint32_t num_children = CalculateNumChildrenIgnoringErrors();649 650  if (idx >= num_children)651    return lldb::ValueObjectSP();652 653  if (m_children.empty()) {654    // do the scan phase655    lldb::addr_t key_at_idx = 0, val_at_idx = 0;656 657    uint32_t tries = 0;658    uint32_t test_idx = 0;659 660    while (tries < num_children) {661      key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);662      val_at_idx = key_at_idx + m_ptr_size;663      ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();664      if (!process_sp)665        return lldb::ValueObjectSP();666      Status error;667      key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);668      if (error.Fail())669        return lldb::ValueObjectSP();670      val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);671      if (error.Fail())672        return lldb::ValueObjectSP();673 674      test_idx++;675 676      if (!key_at_idx || !val_at_idx)677        continue;678      tries++;679 680      DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,681                                             lldb::ValueObjectSP()};682 683      m_children.push_back(descriptor);684    }685  }686 687  if (idx >= m_children.size()) // should never happen688    return lldb::ValueObjectSP();689 690  DictionaryItemDescriptor &dict_item = m_children[idx];691  if (!dict_item.valobj_sp) {692    if (!m_pair_type.IsValid()) {693      TargetSP target_sp(m_backend.GetTargetSP());694      if (!target_sp)695        return ValueObjectSP();696      m_pair_type = GetLLDBNSPairType(target_sp);697    }698    if (!m_pair_type.IsValid())699      return ValueObjectSP();700 701    WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));702 703    if (m_ptr_size == 8) {704      uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();705      *data_ptr = dict_item.key_ptr;706      *(data_ptr + 1) = dict_item.val_ptr;707    } else {708      uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();709      *data_ptr = dict_item.key_ptr;710      *(data_ptr + 1) = dict_item.val_ptr;711    }712 713    StreamString idx_name;714    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);715    DataExtractor data(buffer_sp, m_order, m_ptr_size);716    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,717                                                    m_exe_ctx_ref, m_pair_type);718  }719  return dict_item.valobj_sp;720}721 722lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::723    NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)724    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),725      m_pair_type() {}726 727llvm::Expected<size_t> lldb_private::formatters::728    NSCFDictionarySyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {729  auto optional_idx = ExtractIndexFromString(name.AsCString());730  if (!optional_idx) {731    return llvm::createStringError("Type has no child named '%s'",732                                   name.AsCString());733  }734  uint32_t idx = *optional_idx;735  if (idx >= CalculateNumChildrenIgnoringErrors())736    return llvm::createStringError("Type has no child named '%s'",737                                   name.AsCString());738  return idx;739}740 741llvm::Expected<uint32_t> lldb_private::formatters::742    NSCFDictionarySyntheticFrontEnd::CalculateNumChildren() {743  if (!m_hashtable.IsValid())744    return 0;745  return m_hashtable.GetCount();746}747 748lldb::ChildCacheState749lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {750  m_children.clear();751  ValueObjectSP valobj_sp = m_backend.GetSP();752  m_ptr_size = 0;753  if (!valobj_sp)754    return lldb::ChildCacheState::eRefetch;755  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();756 757  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());758  if (!process_sp)759    return lldb::ChildCacheState::eRefetch;760  m_ptr_size = process_sp->GetAddressByteSize();761  m_order = process_sp->GetByteOrder();762  return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)763             ? lldb::ChildCacheState::eReuse764             : lldb::ChildCacheState::eRefetch;765}766 767lldb::ValueObjectSP768lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(769    uint32_t idx) {770  lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer();771  lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();772 773  const uint32_t num_children = CalculateNumChildrenIgnoringErrors();774 775  if (idx >= num_children)776    return lldb::ValueObjectSP();777 778  if (m_children.empty()) {779    ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();780    if (!process_sp)781      return lldb::ValueObjectSP();782 783    Status error;784    lldb::addr_t key_at_idx = 0, val_at_idx = 0;785 786    uint32_t tries = 0;787    uint32_t test_idx = 0;788 789    // Iterate over inferior memory, reading key/value pointers by shifting each790    // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read791    // fails, otherwise, continue until the number of tries matches the number792    // of childen.793    while (tries < num_children) {794      key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);795      val_at_idx = m_values_ptr + (test_idx * m_ptr_size);796 797      key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);798      if (error.Fail())799        return lldb::ValueObjectSP();800      val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);801      if (error.Fail())802        return lldb::ValueObjectSP();803 804      test_idx++;805 806      if (!key_at_idx || !val_at_idx)807        continue;808      tries++;809 810      DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,811                                             lldb::ValueObjectSP()};812 813      m_children.push_back(descriptor);814    }815  }816 817  if (idx >= m_children.size()) // should never happen818    return lldb::ValueObjectSP();819 820  DictionaryItemDescriptor &dict_item = m_children[idx];821  if (!dict_item.valobj_sp) {822    if (!m_pair_type.IsValid()) {823      TargetSP target_sp(m_backend.GetTargetSP());824      if (!target_sp)825        return ValueObjectSP();826      m_pair_type = GetLLDBNSPairType(target_sp);827    }828    if (!m_pair_type.IsValid())829      return ValueObjectSP();830 831    WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));832 833    switch (m_ptr_size) {834    case 0: // architecture has no clue - fail835      return lldb::ValueObjectSP();836    case 4: {837      uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes());838      *data_ptr = dict_item.key_ptr;839      *(data_ptr + 1) = dict_item.val_ptr;840    } break;841    case 8: {842      uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes());843      *data_ptr = dict_item.key_ptr;844      *(data_ptr + 1) = dict_item.val_ptr;845    } break;846    default:847      lldbassert(false && "pointer size is not 4 nor 8");848    }849 850    StreamString idx_name;851    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);852    DataExtractor data(buffer_sp, m_order, m_ptr_size);853    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,854                                                    m_exe_ctx_ref, m_pair_type);855  }856  return dict_item.valobj_sp;857}858 859lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::860    NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)861    : SyntheticChildrenFrontEnd(*valobj_sp) {}862 863llvm::Expected<size_t>864lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::865    GetIndexOfChildWithName(ConstString name) {866  auto optional_idx = ExtractIndexFromString(name.AsCString());867  if (!optional_idx) {868    return llvm::createStringError("Type has no child named '%s'",869                                   name.AsCString());870  }871  uint32_t idx = *optional_idx;872  if (idx >= CalculateNumChildrenIgnoringErrors())873    return llvm::createStringError("Type has no child named '%s'",874                                   name.AsCString());875  return idx;876}877 878llvm::Expected<uint32_t> lldb_private::formatters::879    NSConstantDictionarySyntheticFrontEnd::CalculateNumChildren() {880  return m_size;881}882 883lldb::ChildCacheState884lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() {885  ValueObjectSP valobj_sp = m_backend.GetSP();886  if (!valobj_sp)887    return lldb::ChildCacheState::eRefetch;888  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();889  Status error;890  error.Clear();891  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());892  if (!process_sp)893    return lldb::ChildCacheState::eRefetch;894  m_ptr_size = process_sp->GetAddressByteSize();895  m_order = process_sp->GetByteOrder();896  uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0);897  m_size = process_sp->ReadUnsignedIntegerFromMemory(898      valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error);899  if (error.Fail())900    return lldb::ChildCacheState::eRefetch;901  m_keys_ptr =902      process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size, error);903  if (error.Fail())904    return lldb::ChildCacheState::eRefetch;905  m_objects_ptr =906      process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size, error);907 908  return error.Success() ? lldb::ChildCacheState::eReuse909                         : lldb::ChildCacheState::eRefetch;910}911 912lldb::ValueObjectSP lldb_private::formatters::913    NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {914  uint32_t num_children = CalculateNumChildrenIgnoringErrors();915 916  if (idx >= num_children)917    return lldb::ValueObjectSP();918 919  if (m_children.empty()) {920    // do the scan phase921    lldb::addr_t key_at_idx = 0, val_at_idx = 0;922    ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();923    if (!process_sp)924      return lldb::ValueObjectSP();925 926    for (unsigned int child = 0; child < num_children; ++child) {927      Status error;928      key_at_idx = process_sp->ReadPointerFromMemory(929          m_keys_ptr + child * m_ptr_size, error);930      if (error.Fail())931        return lldb::ValueObjectSP();932      val_at_idx = process_sp->ReadPointerFromMemory(933          m_objects_ptr + child * m_ptr_size, error);934      if (error.Fail())935        return lldb::ValueObjectSP();936      DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,937                                             lldb::ValueObjectSP()};938      m_children.push_back(descriptor);939    }940  }941 942  if (idx >= m_children.size()) // should never happen943    return lldb::ValueObjectSP();944 945  DictionaryItemDescriptor &dict_item = m_children[idx];946  if (!dict_item.valobj_sp) {947    if (!m_pair_type.IsValid()) {948      TargetSP target_sp(m_backend.GetTargetSP());949      if (!target_sp)950        return ValueObjectSP();951      m_pair_type = GetLLDBNSPairType(target_sp);952    }953    if (!m_pair_type.IsValid())954      return ValueObjectSP();955 956    WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));957 958    if (m_ptr_size == 8) {959      uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();960      *data_ptr = dict_item.key_ptr;961      *(data_ptr + 1) = dict_item.val_ptr;962    } else {963      uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();964      *data_ptr = dict_item.key_ptr;965      *(data_ptr + 1) = dict_item.val_ptr;966    }967 968    StreamString idx_name;969    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);970    DataExtractor data(buffer_sp, m_order, m_ptr_size);971    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,972                                                    m_exe_ctx_ref, m_pair_type);973  }974  return dict_item.valobj_sp;975}976 977lldb_private::formatters::NSDictionary1SyntheticFrontEnd::978    NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)979    : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}980 981llvm::Expected<size_t> lldb_private::formatters::982    NSDictionary1SyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {983  static const ConstString g_zero("[0]");984  if (name == g_zero)985    return 0;986  return llvm::createStringError("Type has no child named '%s'",987                                 name.AsCString());988}989 990llvm::Expected<uint32_t> lldb_private::formatters::991    NSDictionary1SyntheticFrontEnd::CalculateNumChildren() {992  return 1;993}994 995lldb::ChildCacheState996lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {997  m_pair.reset();998  return lldb::ChildCacheState::eRefetch;999}1000 1001lldb::ValueObjectSP1002lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(1003    uint32_t idx) {1004  if (idx != 0)1005    return lldb::ValueObjectSP();1006 1007  if (m_pair.get())1008    return m_pair;1009 1010  auto process_sp(m_backend.GetProcessSP());1011  if (!process_sp)1012    return nullptr;1013 1014  auto ptr_size = process_sp->GetAddressByteSize();1015 1016  lldb::addr_t key_ptr =1017      m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;1018  lldb::addr_t value_ptr = key_ptr + ptr_size;1019 1020  Status error;1021 1022  lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);1023  if (error.Fail())1024    return nullptr;1025  lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);1026  if (error.Fail())1027    return nullptr;1028 1029  auto pair_type =1030      GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());1031 1032  WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));1033 1034  if (ptr_size == 8) {1035    uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();1036    *data_ptr = key_at_idx;1037    *(data_ptr + 1) = value_at_idx;1038  } else {1039    uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();1040    *data_ptr = key_at_idx;1041    *(data_ptr + 1) = value_at_idx;1042  }1043 1044  DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);1045  m_pair = CreateValueObjectFromData(1046      "[0]", data, m_backend.GetExecutionContextRef(), pair_type);1047 1048  return m_pair;1049}1050 1051template <typename D32, typename D64>1052lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32, D64>::1053    GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)1054    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),1055      m_data_32(nullptr), m_data_64(nullptr), m_pair_type() {}1056 1057template <typename D32, typename D64>1058lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<1059    D32, D64>::GenericNSDictionaryMSyntheticFrontEnd::1060    ~GenericNSDictionaryMSyntheticFrontEnd() {1061  delete m_data_32;1062  m_data_32 = nullptr;1063  delete m_data_64;1064  m_data_64 = nullptr;1065}1066 1067template <typename D32, typename D64>1068llvm::Expected<size_t>1069lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<1070    D32, D64>::GetIndexOfChildWithName(ConstString name) {1071  auto optional_idx = ExtractIndexFromString(name.AsCString());1072  if (!optional_idx) {1073    return llvm::createStringError("Type has no child named '%s'",1074                                   name.AsCString());1075  }1076  uint32_t idx = *optional_idx;1077  if (idx >= CalculateNumChildrenIgnoringErrors())1078    return llvm::createStringError("Type has no child named '%s'",1079                                   name.AsCString());1080  return idx;1081}1082 1083template <typename D32, typename D64>1084llvm::Expected<uint32_t>1085lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<1086    D32, D64>::CalculateNumChildren() {1087  if (!m_data_32 && !m_data_64)1088    return 0;1089  return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);1090}1091 1092template <typename D32, typename D64>1093lldb::ChildCacheState1094lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,1095                                                                D64>::Update() {1096  m_children.clear();1097  ValueObjectSP valobj_sp = m_backend.GetSP();1098  m_ptr_size = 0;1099  delete m_data_32;1100  m_data_32 = nullptr;1101  delete m_data_64;1102  m_data_64 = nullptr;1103  if (!valobj_sp)1104    return lldb::ChildCacheState::eRefetch;1105  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();1106  Status error;1107  error.Clear();1108  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());1109  if (!process_sp)1110    return lldb::ChildCacheState::eRefetch;1111  m_ptr_size = process_sp->GetAddressByteSize();1112  m_order = process_sp->GetByteOrder();1113  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;1114  if (m_ptr_size == 4) {1115    m_data_32 = new D32();1116    process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),1117                           error);1118  } else {1119    m_data_64 = new D64();1120    process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),1121                           error);1122  }1123 1124  return error.Success() ? lldb::ChildCacheState::eReuse1125                         : lldb::ChildCacheState::eRefetch;1126}1127 1128template <typename D32, typename D64>1129lldb::ValueObjectSP1130lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<1131    D32, D64>::GetChildAtIndex(uint32_t idx) {1132  lldb::addr_t m_keys_ptr;1133  lldb::addr_t m_values_ptr;1134  if (m_data_32) {1135    uint32_t size = m_data_32->GetSize();1136    m_keys_ptr = m_data_32->_buffer;1137    m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);1138  } else {1139    uint32_t size = m_data_64->GetSize();1140    m_keys_ptr = m_data_64->_buffer;1141    m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);1142  }1143 1144  uint32_t num_children = CalculateNumChildrenIgnoringErrors();1145 1146  if (idx >= num_children)1147    return lldb::ValueObjectSP();1148 1149  if (m_children.empty()) {1150    // do the scan phase1151    lldb::addr_t key_at_idx = 0, val_at_idx = 0;1152 1153    uint32_t tries = 0;1154    uint32_t test_idx = 0;1155 1156    while (tries < num_children) {1157      key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);1158      val_at_idx = m_values_ptr + (test_idx * m_ptr_size);1159      ;1160      ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();1161      if (!process_sp)1162        return lldb::ValueObjectSP();1163      Status error;1164      key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);1165      if (error.Fail())1166        return lldb::ValueObjectSP();1167      val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);1168      if (error.Fail())1169        return lldb::ValueObjectSP();1170 1171      test_idx++;1172 1173      if (!key_at_idx || !val_at_idx)1174        continue;1175      tries++;1176 1177      DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,1178                                             lldb::ValueObjectSP()};1179 1180      m_children.push_back(descriptor);1181    }1182  }1183 1184  if (idx >= m_children.size()) // should never happen1185    return lldb::ValueObjectSP();1186 1187  DictionaryItemDescriptor &dict_item = m_children[idx];1188  if (!dict_item.valobj_sp) {1189    if (!m_pair_type.IsValid()) {1190      TargetSP target_sp(m_backend.GetTargetSP());1191      if (!target_sp)1192        return ValueObjectSP();1193      m_pair_type = GetLLDBNSPairType(target_sp);1194    }1195    if (!m_pair_type.IsValid())1196      return ValueObjectSP();1197 1198    WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));1199 1200    if (m_ptr_size == 8) {1201      uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();1202      *data_ptr = dict_item.key_ptr;1203      *(data_ptr + 1) = dict_item.val_ptr;1204    } else {1205      uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();1206      *data_ptr = dict_item.key_ptr;1207      *(data_ptr + 1) = dict_item.val_ptr;1208    }1209 1210    StreamString idx_name;1211    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);1212    DataExtractor data(buffer_sp, m_order, m_ptr_size);1213    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,1214                                                    m_exe_ctx_ref, m_pair_type);1215  }1216  return dict_item.valobj_sp;1217}1218 1219lldb_private::formatters::Foundation1100::NSDictionaryMSyntheticFrontEnd::1220    NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)1221    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}1222 1223lldb_private::formatters::Foundation1100::1224  NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {1225  delete m_data_32;1226  m_data_32 = nullptr;1227  delete m_data_64;1228  m_data_64 = nullptr;1229}1230 1231llvm::Expected<size_t> lldb_private::formatters::Foundation1100::1232    NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {1233  auto optional_idx = ExtractIndexFromString(name.AsCString());1234  if (!optional_idx) {1235    return llvm::createStringError("Type has no child named '%s'",1236                                   name.AsCString());1237  }1238  uint32_t idx = *optional_idx;1239  if (idx >= CalculateNumChildrenIgnoringErrors())1240    return llvm::createStringError("Type has no child named '%s'",1241                                   name.AsCString());1242  return idx;1243}1244 1245llvm::Expected<uint32_t> lldb_private::formatters::Foundation1100::1246    NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {1247  if (!m_data_32 && !m_data_64)1248    return 0;1249  return (m_data_32 ? m_data_32->_used : m_data_64->_used);1250}1251 1252lldb::ChildCacheState lldb_private::formatters::Foundation1100::1253    NSDictionaryMSyntheticFrontEnd::Update() {1254  m_children.clear();1255  ValueObjectSP valobj_sp = m_backend.GetSP();1256  m_ptr_size = 0;1257  delete m_data_32;1258  m_data_32 = nullptr;1259  delete m_data_64;1260  m_data_64 = nullptr;1261  if (!valobj_sp)1262    return lldb::ChildCacheState::eRefetch;1263  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();1264  Status error;1265  error.Clear();1266  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());1267  if (!process_sp)1268    return lldb::ChildCacheState::eRefetch;1269  m_ptr_size = process_sp->GetAddressByteSize();1270  m_order = process_sp->GetByteOrder();1271  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;1272  if (m_ptr_size == 4) {1273    m_data_32 = new DataDescriptor_32();1274    process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),1275                           error);1276  } else {1277    m_data_64 = new DataDescriptor_64();1278    process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),1279                           error);1280  }1281 1282  return error.Success() ? lldb::ChildCacheState::eReuse1283                         : lldb::ChildCacheState::eRefetch;1284}1285 1286lldb::ValueObjectSP1287lldb_private::formatters::Foundation1100::1288  NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {1289  lldb::addr_t m_keys_ptr =1290      (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);1291  lldb::addr_t m_values_ptr =1292      (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);1293 1294  uint32_t num_children = CalculateNumChildrenIgnoringErrors();1295 1296  if (idx >= num_children)1297    return lldb::ValueObjectSP();1298 1299  if (m_children.empty()) {1300    // do the scan phase1301    lldb::addr_t key_at_idx = 0, val_at_idx = 0;1302 1303    uint32_t tries = 0;1304    uint32_t test_idx = 0;1305 1306    while (tries < num_children) {1307      key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);1308      val_at_idx = m_values_ptr + (test_idx * m_ptr_size);1309      ;1310      ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();1311      if (!process_sp)1312        return lldb::ValueObjectSP();1313      Status error;1314      key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);1315      if (error.Fail())1316        return lldb::ValueObjectSP();1317      val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);1318      if (error.Fail())1319        return lldb::ValueObjectSP();1320 1321      test_idx++;1322 1323      if (!key_at_idx || !val_at_idx)1324        continue;1325      tries++;1326 1327      DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,1328                                             lldb::ValueObjectSP()};1329 1330      m_children.push_back(descriptor);1331    }1332  }1333 1334  if (idx >= m_children.size()) // should never happen1335    return lldb::ValueObjectSP();1336 1337  DictionaryItemDescriptor &dict_item = m_children[idx];1338  if (!dict_item.valobj_sp) {1339    if (!m_pair_type.IsValid()) {1340      TargetSP target_sp(m_backend.GetTargetSP());1341      if (!target_sp)1342        return ValueObjectSP();1343      m_pair_type = GetLLDBNSPairType(target_sp);1344    }1345    if (!m_pair_type.IsValid())1346      return ValueObjectSP();1347 1348    WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));1349 1350    if (m_ptr_size == 8) {1351      uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();1352      *data_ptr = dict_item.key_ptr;1353      *(data_ptr + 1) = dict_item.val_ptr;1354    } else {1355      uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();1356      *data_ptr = dict_item.key_ptr;1357      *(data_ptr + 1) = dict_item.val_ptr;1358    }1359 1360    StreamString idx_name;1361    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);1362    DataExtractor data(buffer_sp, m_order, m_ptr_size);1363    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,1364                                                    m_exe_ctx_ref, m_pair_type);1365  }1366  return dict_item.valobj_sp;1367}1368 1369template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(1370    ValueObject &, Stream &, const TypeSummaryOptions &);1371 1372template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(1373    ValueObject &, Stream &, const TypeSummaryOptions &);1374