1 //===-- NSDictionary.cpp ----------------------------------------*- C++ -*-===//
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-exception
7 //===----------------------------------------------------------------------===//
11 #include "clang/AST/DeclCXX.h"
13 #include "NSDictionary.h"
15 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
17 #include "lldb/Core/ValueObject.h"
18 #include "lldb/Core/ValueObjectConstResult.h"
19 #include "lldb/DataFormatters/FormattersHelpers.h"
20 #include "lldb/Symbol/ClangASTContext.h"
21 #include "lldb/Target/Language.h"
22 #include "lldb/Target/StackFrame.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Utility/DataBufferHeap.h"
25 #include "lldb/Utility/Endian.h"
26 #include "lldb/Utility/Status.h"
27 #include "lldb/Utility/Stream.h"
30 using namespace lldb_private;
31 using namespace lldb_private::formatters;
33 NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
37 bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(
38 ConstString class_name) {
39 return class_name.GetStringRef().startswith(m_prefix.GetStringRef());
42 NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)
45 bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match(
46 ConstString class_name) {
47 return (class_name == m_name);
50 NSDictionary_Additionals::AdditionalFormatters<
51 CXXFunctionSummaryFormat::Callback> &
52 NSDictionary_Additionals::GetAdditionalSummaries() {
53 static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map;
57 NSDictionary_Additionals::AdditionalFormatters<
58 CXXSyntheticChildren::CreateFrontEndCallback> &
59 NSDictionary_Additionals::GetAdditionalSynthetics() {
60 static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback>
65 static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
66 CompilerType compiler_type;
68 ClangASTContext *target_ast_context = ClangASTContext::GetScratch(*target_sp);
70 if (target_ast_context) {
71 ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
74 target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(
75 g___lldb_autogen_nspair);
78 compiler_type = target_ast_context->CreateRecordType(
79 nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(),
80 clang::TTK_Struct, lldb::eLanguageTypeC);
83 ClangASTContext::StartTagDeclarationDefinition(compiler_type);
84 CompilerType id_compiler_type =
85 target_ast_context->GetBasicType(eBasicTypeObjCID);
86 ClangASTContext::AddFieldToRecordType(
87 compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
88 ClangASTContext::AddFieldToRecordType(
89 compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
90 ClangASTContext::CompleteTagDeclarationDefinition(compiler_type);
97 namespace lldb_private {
98 namespace formatters {
99 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
101 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
103 ~NSDictionaryISyntheticFrontEnd() override;
105 size_t CalculateNumChildren() override;
107 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
109 bool Update() override;
111 bool MightHaveChildren() override;
113 size_t GetIndexOfChildWithName(ConstString name) override;
116 struct DataDescriptor_32 {
121 struct DataDescriptor_64 {
126 struct DictionaryItemDescriptor {
127 lldb::addr_t key_ptr;
128 lldb::addr_t val_ptr;
129 lldb::ValueObjectSP valobj_sp;
132 ExecutionContextRef m_exe_ctx_ref;
134 lldb::ByteOrder m_order;
135 DataDescriptor_32 *m_data_32;
136 DataDescriptor_64 *m_data_64;
137 lldb::addr_t m_data_ptr;
138 CompilerType m_pair_type;
139 std::vector<DictionaryItemDescriptor> m_children;
142 class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
144 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
146 ~NSDictionary1SyntheticFrontEnd() override = default;
148 size_t CalculateNumChildren() override;
150 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
152 bool Update() override;
154 bool MightHaveChildren() override;
156 size_t GetIndexOfChildWithName(ConstString name) override;
159 ValueObjectSP m_pair;
162 template <typename D32, typename D64>
163 class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
165 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
167 ~GenericNSDictionaryMSyntheticFrontEnd() override;
169 size_t CalculateNumChildren() override;
171 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
173 bool Update() override;
175 bool MightHaveChildren() override;
177 size_t GetIndexOfChildWithName(ConstString name) override;
180 struct DictionaryItemDescriptor {
181 lldb::addr_t key_ptr;
182 lldb::addr_t val_ptr;
183 lldb::ValueObjectSP valobj_sp;
186 ExecutionContextRef m_exe_ctx_ref;
188 lldb::ByteOrder m_order;
191 CompilerType m_pair_type;
192 std::vector<DictionaryItemDescriptor> m_children;
195 namespace Foundation1100 {
196 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
198 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
200 ~NSDictionaryMSyntheticFrontEnd() override;
202 size_t CalculateNumChildren() override;
204 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
206 bool Update() override;
208 bool MightHaveChildren() override;
210 size_t GetIndexOfChildWithName(ConstString name) override;
213 struct DataDescriptor_32 {
222 struct DataDescriptor_64 {
231 struct DictionaryItemDescriptor {
232 lldb::addr_t key_ptr;
233 lldb::addr_t val_ptr;
234 lldb::ValueObjectSP valobj_sp;
237 ExecutionContextRef m_exe_ctx_ref;
239 lldb::ByteOrder m_order;
240 DataDescriptor_32 *m_data_32;
241 DataDescriptor_64 *m_data_64;
242 CompilerType m_pair_type;
243 std::vector<DictionaryItemDescriptor> m_children;
247 namespace Foundation1428 {
248 struct DataDescriptor_32 {
253 uint64_t GetSize() { return _size; }
256 struct DataDescriptor_64 {
261 uint64_t GetSize() { return _size; }
266 using NSDictionaryMSyntheticFrontEnd =
267 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
270 namespace Foundation1437 {
271 static const uint64_t NSDictionaryCapacities[] = {
272 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
273 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
274 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
275 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
276 111638519, 180634607, 292272623, 472907251
279 static const size_t NSDictionaryNumSizeBuckets = sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
281 struct DataDescriptor_32 {
289 return (_szidx) >= NSDictionaryNumSizeBuckets ?
290 0 : NSDictionaryCapacities[_szidx];
294 struct DataDescriptor_64 {
302 return (_szidx) >= NSDictionaryNumSizeBuckets ?
303 0 : NSDictionaryCapacities[_szidx];
307 using NSDictionaryMSyntheticFrontEnd =
308 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
310 template <typename DD>
312 __NSDictionaryMSize_Impl(lldb_private::Process &process,
313 lldb::addr_t valobj_addr, Status &error) {
314 const lldb::addr_t start_of_descriptor =
315 valobj_addr + process.GetAddressByteSize();
316 DD descriptor = DD();
317 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
322 return descriptor._used;
326 __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
328 if (process.GetAddressByteSize() == 4) {
329 return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
332 return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
338 } // namespace formatters
339 } // namespace lldb_private
341 template <bool name_entries>
342 bool lldb_private::formatters::NSDictionarySummaryProvider(
343 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
344 static ConstString g_TypeHint("NSDictionary");
345 ProcessSP process_sp = valobj.GetProcessSP();
349 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
354 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
355 runtime->GetClassDescriptor(valobj));
357 if (!descriptor || !descriptor->IsValid())
360 uint32_t ptr_size = process_sp->GetAddressByteSize();
361 bool is_64bit = (ptr_size == 8);
363 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
370 ConstString class_name(descriptor->GetClassName());
372 static const ConstString g_DictionaryI("__NSDictionaryI");
373 static const ConstString g_DictionaryM("__NSDictionaryM");
374 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
375 static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
376 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
377 static const ConstString g_Dictionary0("__NSDictionary0");
378 static const ConstString g_DictionaryCF("__NSCFDictionary");
380 if (class_name.IsEmpty())
383 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
385 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
389 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
390 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
391 class_name == g_DictionaryCF) {
392 AppleObjCRuntime *apple_runtime =
393 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
395 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
396 value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
399 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
401 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
405 } else if (class_name == g_Dictionary1) {
407 } else if (class_name == g_Dictionary0) {
411 auto &map(NSDictionary_Additionals::GetAdditionalSummaries());
412 for (auto &candidate : map) {
413 if (candidate.first && candidate.first->Match(class_name))
414 return candidate.second(valobj, stream, options);
419 std::string prefix, suffix;
420 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
421 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
428 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair",
429 value == 1 ? "" : "s", suffix.c_str());
433 SyntheticChildrenFrontEnd *
434 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
435 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
436 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
439 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
440 ObjCLanguageRuntime::Get(*process_sp));
444 CompilerType valobj_type(valobj_sp->GetCompilerType());
445 Flags flags(valobj_type.GetTypeInfo());
447 if (flags.IsClear(eTypeIsPointer)) {
449 valobj_sp = valobj_sp->AddressOf(error);
450 if (error.Fail() || !valobj_sp)
454 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
455 runtime->GetClassDescriptor(*valobj_sp));
457 if (!descriptor || !descriptor->IsValid())
460 ConstString class_name(descriptor->GetClassName());
462 static const ConstString g_DictionaryI("__NSDictionaryI");
463 static const ConstString g_DictionaryM("__NSDictionaryM");
464 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
465 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
466 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
467 static const ConstString g_Dictionary0("__NSDictionary0");
469 if (class_name.IsEmpty())
472 if (class_name == g_DictionaryI) {
473 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
474 } else if (class_name == g_DictionaryM) {
475 if (runtime->GetFoundationVersion() >= 1437) {
476 return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
477 } else if (runtime->GetFoundationVersion() >= 1428) {
478 return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));
480 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
482 } else if (class_name == g_DictionaryMLegacy) {
483 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
484 } else if (class_name == g_Dictionary1) {
485 return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
487 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());
488 for (auto &candidate : map) {
489 if (candidate.first && candidate.first->Match((class_name)))
490 return candidate.second(synth, valobj_sp);
497 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
498 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
499 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
500 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
503 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
504 ~NSDictionaryISyntheticFrontEnd() {
511 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
512 GetIndexOfChildWithName(ConstString name) {
513 const char *item_name = name.GetCString();
514 uint32_t idx = ExtractIndexFromString(item_name);
515 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
520 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
521 CalculateNumChildren() {
522 if (!m_data_32 && !m_data_64)
524 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
527 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
534 ValueObjectSP valobj_sp = m_backend.GetSP();
537 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
540 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
543 m_ptr_size = process_sp->GetAddressByteSize();
544 m_order = process_sp->GetByteOrder();
545 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
546 if (m_ptr_size == 4) {
547 m_data_32 = new DataDescriptor_32();
548 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
551 m_data_64 = new DataDescriptor_64();
552 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
557 m_data_ptr = data_location + m_ptr_size;
561 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
562 MightHaveChildren() {
567 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
569 uint32_t num_children = CalculateNumChildren();
571 if (idx >= num_children)
572 return lldb::ValueObjectSP();
574 if (m_children.empty()) {
576 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
579 uint32_t test_idx = 0;
581 while (tries < num_children) {
582 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
583 val_at_idx = key_at_idx + m_ptr_size;
584 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
586 return lldb::ValueObjectSP();
588 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
590 return lldb::ValueObjectSP();
591 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
593 return lldb::ValueObjectSP();
597 if (!key_at_idx || !val_at_idx)
601 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
602 lldb::ValueObjectSP()};
604 m_children.push_back(descriptor);
608 if (idx >= m_children.size()) // should never happen
609 return lldb::ValueObjectSP();
611 DictionaryItemDescriptor &dict_item = m_children[idx];
612 if (!dict_item.valobj_sp) {
613 if (!m_pair_type.IsValid()) {
614 TargetSP target_sp(m_backend.GetTargetSP());
616 return ValueObjectSP();
617 m_pair_type = GetLLDBNSPairType(target_sp);
619 if (!m_pair_type.IsValid())
620 return ValueObjectSP();
622 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
624 if (m_ptr_size == 8) {
625 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
626 *data_ptr = dict_item.key_ptr;
627 *(data_ptr + 1) = dict_item.val_ptr;
629 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
630 *data_ptr = dict_item.key_ptr;
631 *(data_ptr + 1) = dict_item.val_ptr;
634 StreamString idx_name;
635 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
636 DataExtractor data(buffer_sp, m_order, m_ptr_size);
637 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
638 m_exe_ctx_ref, m_pair_type);
640 return dict_item.valobj_sp;
643 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
644 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
645 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
647 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
648 GetIndexOfChildWithName(ConstString name) {
649 static const ConstString g_zero("[0]");
650 return name == g_zero ? 0 : UINT32_MAX;
653 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
654 CalculateNumChildren() {
658 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
663 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
664 MightHaveChildren() {
669 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
672 return lldb::ValueObjectSP();
677 auto process_sp(m_backend.GetProcessSP());
681 auto ptr_size = process_sp->GetAddressByteSize();
683 lldb::addr_t key_ptr =
684 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
685 lldb::addr_t value_ptr = key_ptr + ptr_size;
689 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
692 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
697 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
699 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
702 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
703 *data_ptr = key_at_idx;
704 *(data_ptr + 1) = value_at_idx;
706 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
707 *data_ptr = key_at_idx;
708 *(data_ptr + 1) = value_at_idx;
711 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
712 m_pair = CreateValueObjectFromData(
713 "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
718 template <typename D32, typename D64>
719 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
720 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
721 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
722 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
725 template <typename D32, typename D64>
726 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
727 ~GenericNSDictionaryMSyntheticFrontEnd() {
734 template <typename D32, typename D64>
736 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: GetIndexOfChildWithName(ConstString name) {
737 const char *item_name = name.GetCString();
738 uint32_t idx = ExtractIndexFromString(item_name);
739 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
744 template <typename D32, typename D64>
746 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() {
747 if (!m_data_32 && !m_data_64)
749 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
752 template <typename D32, typename D64>
754 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
757 ValueObjectSP valobj_sp = m_backend.GetSP();
765 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
768 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
771 m_ptr_size = process_sp->GetAddressByteSize();
772 m_order = process_sp->GetByteOrder();
773 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
774 if (m_ptr_size == 4) {
775 m_data_32 = new D32();
776 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
779 m_data_64 = new D64();
780 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
788 template <typename D32, typename D64>
790 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
791 MightHaveChildren() {
795 template <typename D32, typename D64>
797 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
800 lldb::addr_t m_keys_ptr;
801 lldb::addr_t m_values_ptr;
803 uint32_t size = m_data_32->GetSize();
804 m_keys_ptr = m_data_32->_buffer;
805 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
807 uint32_t size = m_data_64->GetSize();
808 m_keys_ptr = m_data_64->_buffer;
809 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
812 uint32_t num_children = CalculateNumChildren();
814 if (idx >= num_children)
815 return lldb::ValueObjectSP();
817 if (m_children.empty()) {
819 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
822 uint32_t test_idx = 0;
824 while (tries < num_children) {
825 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
826 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
828 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
830 return lldb::ValueObjectSP();
832 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
834 return lldb::ValueObjectSP();
835 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
837 return lldb::ValueObjectSP();
841 if (!key_at_idx || !val_at_idx)
845 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
846 lldb::ValueObjectSP()};
848 m_children.push_back(descriptor);
852 if (idx >= m_children.size()) // should never happen
853 return lldb::ValueObjectSP();
855 DictionaryItemDescriptor &dict_item = m_children[idx];
856 if (!dict_item.valobj_sp) {
857 if (!m_pair_type.IsValid()) {
858 TargetSP target_sp(m_backend.GetTargetSP());
860 return ValueObjectSP();
861 m_pair_type = GetLLDBNSPairType(target_sp);
863 if (!m_pair_type.IsValid())
864 return ValueObjectSP();
866 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
868 if (m_ptr_size == 8) {
869 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
870 *data_ptr = dict_item.key_ptr;
871 *(data_ptr + 1) = dict_item.val_ptr;
873 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
874 *data_ptr = dict_item.key_ptr;
875 *(data_ptr + 1) = dict_item.val_ptr;
878 StreamString idx_name;
879 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
880 DataExtractor data(buffer_sp, m_order, m_ptr_size);
881 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
882 m_exe_ctx_ref, m_pair_type);
884 return dict_item.valobj_sp;
888 lldb_private::formatters::Foundation1100::
889 NSDictionaryMSyntheticFrontEnd::
890 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
891 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
892 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
895 lldb_private::formatters::Foundation1100::
896 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {
904 lldb_private::formatters::Foundation1100::
905 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
906 const char *item_name = name.GetCString();
907 uint32_t idx = ExtractIndexFromString(item_name);
908 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
914 lldb_private::formatters::Foundation1100::
915 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
916 if (!m_data_32 && !m_data_64)
918 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
922 lldb_private::formatters::Foundation1100::
923 NSDictionaryMSyntheticFrontEnd::Update() {
925 ValueObjectSP valobj_sp = m_backend.GetSP();
933 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
936 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
939 m_ptr_size = process_sp->GetAddressByteSize();
940 m_order = process_sp->GetByteOrder();
941 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
942 if (m_ptr_size == 4) {
943 m_data_32 = new DataDescriptor_32();
944 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
947 m_data_64 = new DataDescriptor_64();
948 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
957 lldb_private::formatters::Foundation1100::
958 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
963 lldb_private::formatters::Foundation1100::
964 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
965 lldb::addr_t m_keys_ptr =
966 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
967 lldb::addr_t m_values_ptr =
968 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
970 uint32_t num_children = CalculateNumChildren();
972 if (idx >= num_children)
973 return lldb::ValueObjectSP();
975 if (m_children.empty()) {
977 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
980 uint32_t test_idx = 0;
982 while (tries < num_children) {
983 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
984 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
986 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
988 return lldb::ValueObjectSP();
990 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
992 return lldb::ValueObjectSP();
993 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
995 return lldb::ValueObjectSP();
999 if (!key_at_idx || !val_at_idx)
1003 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1004 lldb::ValueObjectSP()};
1006 m_children.push_back(descriptor);
1010 if (idx >= m_children.size()) // should never happen
1011 return lldb::ValueObjectSP();
1013 DictionaryItemDescriptor &dict_item = m_children[idx];
1014 if (!dict_item.valobj_sp) {
1015 if (!m_pair_type.IsValid()) {
1016 TargetSP target_sp(m_backend.GetTargetSP());
1018 return ValueObjectSP();
1019 m_pair_type = GetLLDBNSPairType(target_sp);
1021 if (!m_pair_type.IsValid())
1022 return ValueObjectSP();
1024 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1026 if (m_ptr_size == 8) {
1027 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1028 *data_ptr = dict_item.key_ptr;
1029 *(data_ptr + 1) = dict_item.val_ptr;
1031 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1032 *data_ptr = dict_item.key_ptr;
1033 *(data_ptr + 1) = dict_item.val_ptr;
1036 StreamString idx_name;
1037 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1038 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1039 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1040 m_exe_ctx_ref, m_pair_type);
1042 return dict_item.valobj_sp;
1045 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(
1046 ValueObject &, Stream &, const TypeSummaryOptions &);
1048 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(
1049 ValueObject &, Stream &, const TypeSummaryOptions &);