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