1 //===-- NSDictionary.cpp ----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
14 // Other libraries and framework includes
15 #include "clang/AST/DeclCXX.h"
18 #include "NSDictionary.h"
20 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
22 #include "lldb/Core/ValueObject.h"
23 #include "lldb/Core/ValueObjectConstResult.h"
24 #include "lldb/DataFormatters/FormattersHelpers.h"
25 #include "lldb/Symbol/ClangASTContext.h"
26 #include "lldb/Target/Language.h"
27 #include "lldb/Target/ObjCLanguageRuntime.h"
28 #include "lldb/Target/StackFrame.h"
29 #include "lldb/Target/Target.h"
30 #include "lldb/Utility/DataBufferHeap.h"
31 #include "lldb/Utility/Endian.h"
32 #include "lldb/Utility/Status.h"
33 #include "lldb/Utility/Stream.h"
36 using namespace lldb_private;
37 using namespace lldb_private::formatters;
39 NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
43 bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(
44 ConstString class_name) {
45 return class_name.GetStringRef().startswith(m_prefix.GetStringRef());
48 NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)
51 bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match(
52 ConstString class_name) {
53 return (class_name == m_name);
56 NSDictionary_Additionals::AdditionalFormatters<
57 CXXFunctionSummaryFormat::Callback> &
58 NSDictionary_Additionals::GetAdditionalSummaries() {
59 static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map;
63 NSDictionary_Additionals::AdditionalFormatters<
64 CXXSyntheticChildren::CreateFrontEndCallback> &
65 NSDictionary_Additionals::GetAdditionalSynthetics() {
66 static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback>
71 static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
72 CompilerType compiler_type;
74 ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext();
76 if (target_ast_context) {
77 ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
80 target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(
81 g___lldb_autogen_nspair);
84 compiler_type = target_ast_context->CreateRecordType(
85 nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(),
86 clang::TTK_Struct, lldb::eLanguageTypeC);
89 ClangASTContext::StartTagDeclarationDefinition(compiler_type);
90 CompilerType id_compiler_type =
91 target_ast_context->GetBasicType(eBasicTypeObjCID);
92 ClangASTContext::AddFieldToRecordType(
93 compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
94 ClangASTContext::AddFieldToRecordType(
95 compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
96 ClangASTContext::CompleteTagDeclarationDefinition(compiler_type);
100 return compiler_type;
103 namespace lldb_private {
104 namespace formatters {
105 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
107 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
109 ~NSDictionaryISyntheticFrontEnd() override;
111 size_t CalculateNumChildren() override;
113 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
115 bool Update() override;
117 bool MightHaveChildren() override;
119 size_t GetIndexOfChildWithName(const ConstString &name) override;
122 struct DataDescriptor_32 {
127 struct DataDescriptor_64 {
132 struct DictionaryItemDescriptor {
133 lldb::addr_t key_ptr;
134 lldb::addr_t val_ptr;
135 lldb::ValueObjectSP valobj_sp;
138 ExecutionContextRef m_exe_ctx_ref;
140 lldb::ByteOrder m_order;
141 DataDescriptor_32 *m_data_32;
142 DataDescriptor_64 *m_data_64;
143 lldb::addr_t m_data_ptr;
144 CompilerType m_pair_type;
145 std::vector<DictionaryItemDescriptor> m_children;
148 class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
150 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
152 ~NSDictionary1SyntheticFrontEnd() override = default;
154 size_t CalculateNumChildren() override;
156 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
158 bool Update() override;
160 bool MightHaveChildren() override;
162 size_t GetIndexOfChildWithName(const ConstString &name) override;
165 ValueObjectSP m_pair;
168 template <typename D32, typename D64>
169 class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
171 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
173 ~GenericNSDictionaryMSyntheticFrontEnd() override;
175 size_t CalculateNumChildren() override;
177 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
179 bool Update() override;
181 bool MightHaveChildren() override;
183 size_t GetIndexOfChildWithName(const ConstString &name) override;
186 struct DictionaryItemDescriptor {
187 lldb::addr_t key_ptr;
188 lldb::addr_t val_ptr;
189 lldb::ValueObjectSP valobj_sp;
192 ExecutionContextRef m_exe_ctx_ref;
194 lldb::ByteOrder m_order;
197 CompilerType m_pair_type;
198 std::vector<DictionaryItemDescriptor> m_children;
201 namespace Foundation1100 {
202 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
204 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
206 ~NSDictionaryMSyntheticFrontEnd() override;
208 size_t CalculateNumChildren() override;
210 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
212 bool Update() override;
214 bool MightHaveChildren() override;
216 size_t GetIndexOfChildWithName(const ConstString &name) override;
219 struct DataDescriptor_32 {
228 struct DataDescriptor_64 {
237 struct DictionaryItemDescriptor {
238 lldb::addr_t key_ptr;
239 lldb::addr_t val_ptr;
240 lldb::ValueObjectSP valobj_sp;
243 ExecutionContextRef m_exe_ctx_ref;
245 lldb::ByteOrder m_order;
246 DataDescriptor_32 *m_data_32;
247 DataDescriptor_64 *m_data_64;
248 CompilerType m_pair_type;
249 std::vector<DictionaryItemDescriptor> m_children;
253 namespace Foundation1428 {
254 struct DataDescriptor_32 {
259 uint64_t GetSize() { return _size; }
262 struct DataDescriptor_64 {
267 uint64_t GetSize() { return _size; }
272 using NSDictionaryMSyntheticFrontEnd =
273 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
276 namespace Foundation1437 {
277 static const uint64_t NSDictionaryCapacities[] = {
278 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
279 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
280 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
281 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
282 111638519, 180634607, 292272623, 472907251
285 static const size_t NSDictionaryNumSizeBuckets = sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
287 struct DataDescriptor_32 {
302 return (_szidx) >= NSDictionaryNumSizeBuckets ?
303 0 : NSDictionaryCapacities[_szidx];
307 struct DataDescriptor_64 {
322 return (_szidx) >= NSDictionaryNumSizeBuckets ?
323 0 : NSDictionaryCapacities[_szidx];
327 using NSDictionaryMSyntheticFrontEnd =
328 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
330 template <typename DD>
332 __NSDictionaryMSize_Impl(lldb_private::Process &process,
333 lldb::addr_t valobj_addr, Status &error) {
334 const lldb::addr_t start_of_descriptor =
335 valobj_addr + process.GetAddressByteSize();
336 DD descriptor = DD();
337 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
342 return descriptor._used;
346 __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
348 if (process.GetAddressByteSize() == 4) {
349 return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
352 return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
358 } // namespace formatters
359 } // namespace lldb_private
361 template <bool name_entries>
362 bool lldb_private::formatters::NSDictionarySummaryProvider(
363 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
364 static ConstString g_TypeHint("NSDictionary");
365 ProcessSP process_sp = valobj.GetProcessSP();
369 ObjCLanguageRuntime *runtime =
370 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
371 lldb::eLanguageTypeObjC);
376 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
377 runtime->GetClassDescriptor(valobj));
379 if (!descriptor || !descriptor->IsValid())
382 uint32_t ptr_size = process_sp->GetAddressByteSize();
383 bool is_64bit = (ptr_size == 8);
385 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
392 ConstString class_name(descriptor->GetClassName());
394 static const ConstString g_DictionaryI("__NSDictionaryI");
395 static const ConstString g_DictionaryM("__NSDictionaryM");
396 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
397 static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
398 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
400 if (class_name.IsEmpty())
403 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
405 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
409 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
410 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) {
411 AppleObjCRuntime *apple_runtime =
412 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
414 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
415 value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
418 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
420 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
424 } else if (class_name == g_Dictionary1) {
427 /*else if (!strcmp(class_name,"__NSCFDictionary"))
430 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ?
431 20 : 12), 4, 0, error);
435 value &= ~0x0f1f000000000000UL;
438 auto &map(NSDictionary_Additionals::GetAdditionalSummaries());
439 for (auto &candidate : map) {
440 if (candidate.first && candidate.first->Match(class_name))
441 return candidate.second(valobj, stream, options);
446 std::string prefix, suffix;
447 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
448 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
455 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair",
456 value == 1 ? "" : "s", suffix.c_str());
460 SyntheticChildrenFrontEnd *
461 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
462 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
463 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
466 AppleObjCRuntime *runtime =
467 llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
471 CompilerType valobj_type(valobj_sp->GetCompilerType());
472 Flags flags(valobj_type.GetTypeInfo());
474 if (flags.IsClear(eTypeIsPointer)) {
476 valobj_sp = valobj_sp->AddressOf(error);
477 if (error.Fail() || !valobj_sp)
481 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
482 runtime->GetClassDescriptor(*valobj_sp));
484 if (!descriptor || !descriptor->IsValid())
487 ConstString class_name(descriptor->GetClassName());
489 static const ConstString g_DictionaryI("__NSDictionaryI");
490 static const ConstString g_DictionaryM("__NSDictionaryM");
491 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
492 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
493 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
495 if (class_name.IsEmpty())
498 if (class_name == g_DictionaryI) {
499 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
500 } else if (class_name == g_DictionaryM) {
501 if (runtime->GetFoundationVersion() >= 1437) {
502 return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
503 } else if (runtime->GetFoundationVersion() >= 1428) {
504 return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));
506 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
508 } else if (class_name == g_DictionaryMLegacy) {
509 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
510 } else if (class_name == g_Dictionary1) {
511 return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
513 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());
514 for (auto &candidate : map) {
515 if (candidate.first && candidate.first->Match((class_name)))
516 return candidate.second(synth, valobj_sp);
523 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
524 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
525 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
526 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
529 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
530 ~NSDictionaryISyntheticFrontEnd() {
537 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
538 GetIndexOfChildWithName(const ConstString &name) {
539 const char *item_name = name.GetCString();
540 uint32_t idx = ExtractIndexFromString(item_name);
541 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
546 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
547 CalculateNumChildren() {
548 if (!m_data_32 && !m_data_64)
550 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
553 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
560 ValueObjectSP valobj_sp = m_backend.GetSP();
563 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
566 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
569 m_ptr_size = process_sp->GetAddressByteSize();
570 m_order = process_sp->GetByteOrder();
571 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
572 if (m_ptr_size == 4) {
573 m_data_32 = new DataDescriptor_32();
574 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
577 m_data_64 = new DataDescriptor_64();
578 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
583 m_data_ptr = data_location + m_ptr_size;
587 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
588 MightHaveChildren() {
593 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
595 uint32_t num_children = CalculateNumChildren();
597 if (idx >= num_children)
598 return lldb::ValueObjectSP();
600 if (m_children.empty()) {
602 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
605 uint32_t test_idx = 0;
607 while (tries < num_children) {
608 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
609 val_at_idx = key_at_idx + m_ptr_size;
610 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
612 return lldb::ValueObjectSP();
614 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
616 return lldb::ValueObjectSP();
617 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
619 return lldb::ValueObjectSP();
623 if (!key_at_idx || !val_at_idx)
627 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
628 lldb::ValueObjectSP()};
630 m_children.push_back(descriptor);
634 if (idx >= m_children.size()) // should never happen
635 return lldb::ValueObjectSP();
637 DictionaryItemDescriptor &dict_item = m_children[idx];
638 if (!dict_item.valobj_sp) {
639 if (!m_pair_type.IsValid()) {
640 TargetSP target_sp(m_backend.GetTargetSP());
642 return ValueObjectSP();
643 m_pair_type = GetLLDBNSPairType(target_sp);
645 if (!m_pair_type.IsValid())
646 return ValueObjectSP();
648 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
650 if (m_ptr_size == 8) {
651 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
652 *data_ptr = dict_item.key_ptr;
653 *(data_ptr + 1) = dict_item.val_ptr;
655 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
656 *data_ptr = dict_item.key_ptr;
657 *(data_ptr + 1) = dict_item.val_ptr;
660 StreamString idx_name;
661 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
662 DataExtractor data(buffer_sp, m_order, m_ptr_size);
663 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
664 m_exe_ctx_ref, m_pair_type);
666 return dict_item.valobj_sp;
669 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
670 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
671 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
673 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
674 GetIndexOfChildWithName(const ConstString &name) {
675 static const ConstString g_zero("[0]");
683 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
684 CalculateNumChildren() {
688 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
693 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
694 MightHaveChildren() {
699 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
702 return lldb::ValueObjectSP();
707 auto process_sp(m_backend.GetProcessSP());
711 auto ptr_size = process_sp->GetAddressByteSize();
713 lldb::addr_t key_ptr =
714 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
715 lldb::addr_t value_ptr = key_ptr + ptr_size;
719 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
722 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
727 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
729 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
732 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
733 *data_ptr = key_at_idx;
734 *(data_ptr + 1) = value_at_idx;
736 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
737 *data_ptr = key_at_idx;
738 *(data_ptr + 1) = value_at_idx;
741 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
742 m_pair = CreateValueObjectFromData(
743 "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
748 template <typename D32, typename D64>
749 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
750 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
751 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
752 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
755 template <typename D32, typename D64>
756 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
757 ~GenericNSDictionaryMSyntheticFrontEnd() {
764 template <typename D32, typename D64>
766 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: GetIndexOfChildWithName(const ConstString &name) {
767 const char *item_name = name.GetCString();
768 uint32_t idx = ExtractIndexFromString(item_name);
769 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
774 template <typename D32, typename D64>
776 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() {
777 if (!m_data_32 && !m_data_64)
779 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
782 template <typename D32, typename D64>
784 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
787 ValueObjectSP valobj_sp = m_backend.GetSP();
795 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
798 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
801 m_ptr_size = process_sp->GetAddressByteSize();
802 m_order = process_sp->GetByteOrder();
803 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
804 if (m_ptr_size == 4) {
805 m_data_32 = new D32();
806 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
809 m_data_64 = new D64();
810 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
818 template <typename D32, typename D64>
820 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
821 MightHaveChildren() {
825 template <typename D32, typename D64>
827 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
830 lldb::addr_t m_keys_ptr;
831 lldb::addr_t m_values_ptr;
833 uint32_t size = m_data_32->GetSize();
834 m_keys_ptr = m_data_32->_buffer;
835 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
837 uint32_t size = m_data_64->GetSize();
838 m_keys_ptr = m_data_64->_buffer;
839 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
842 uint32_t num_children = CalculateNumChildren();
844 if (idx >= num_children)
845 return lldb::ValueObjectSP();
847 if (m_children.empty()) {
849 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
852 uint32_t test_idx = 0;
854 while (tries < num_children) {
855 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
856 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
858 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
860 return lldb::ValueObjectSP();
862 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
864 return lldb::ValueObjectSP();
865 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
867 return lldb::ValueObjectSP();
871 if (!key_at_idx || !val_at_idx)
875 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
876 lldb::ValueObjectSP()};
878 m_children.push_back(descriptor);
882 if (idx >= m_children.size()) // should never happen
883 return lldb::ValueObjectSP();
885 DictionaryItemDescriptor &dict_item = m_children[idx];
886 if (!dict_item.valobj_sp) {
887 if (!m_pair_type.IsValid()) {
888 TargetSP target_sp(m_backend.GetTargetSP());
890 return ValueObjectSP();
891 m_pair_type = GetLLDBNSPairType(target_sp);
893 if (!m_pair_type.IsValid())
894 return ValueObjectSP();
896 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
898 if (m_ptr_size == 8) {
899 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
900 *data_ptr = dict_item.key_ptr;
901 *(data_ptr + 1) = dict_item.val_ptr;
903 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
904 *data_ptr = dict_item.key_ptr;
905 *(data_ptr + 1) = dict_item.val_ptr;
908 StreamString idx_name;
909 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
910 DataExtractor data(buffer_sp, m_order, m_ptr_size);
911 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
912 m_exe_ctx_ref, m_pair_type);
914 return dict_item.valobj_sp;
918 lldb_private::formatters::Foundation1100::
919 NSDictionaryMSyntheticFrontEnd::
920 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
921 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
922 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
925 lldb_private::formatters::Foundation1100::
926 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {
934 lldb_private::formatters::Foundation1100::
935 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(const ConstString &name) {
936 const char *item_name = name.GetCString();
937 uint32_t idx = ExtractIndexFromString(item_name);
938 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
944 lldb_private::formatters::Foundation1100::
945 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
946 if (!m_data_32 && !m_data_64)
948 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
952 lldb_private::formatters::Foundation1100::
953 NSDictionaryMSyntheticFrontEnd::Update() {
955 ValueObjectSP valobj_sp = m_backend.GetSP();
963 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
966 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
969 m_ptr_size = process_sp->GetAddressByteSize();
970 m_order = process_sp->GetByteOrder();
971 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
972 if (m_ptr_size == 4) {
973 m_data_32 = new DataDescriptor_32();
974 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
977 m_data_64 = new DataDescriptor_64();
978 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
987 lldb_private::formatters::Foundation1100::
988 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
993 lldb_private::formatters::Foundation1100::
994 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
995 lldb::addr_t m_keys_ptr =
996 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
997 lldb::addr_t m_values_ptr =
998 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
1000 uint32_t num_children = CalculateNumChildren();
1002 if (idx >= num_children)
1003 return lldb::ValueObjectSP();
1005 if (m_children.empty()) {
1006 // do the scan phase
1007 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1010 uint32_t test_idx = 0;
1012 while (tries < num_children) {
1013 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1014 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1016 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1018 return lldb::ValueObjectSP();
1020 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1022 return lldb::ValueObjectSP();
1023 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1025 return lldb::ValueObjectSP();
1029 if (!key_at_idx || !val_at_idx)
1033 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1034 lldb::ValueObjectSP()};
1036 m_children.push_back(descriptor);
1040 if (idx >= m_children.size()) // should never happen
1041 return lldb::ValueObjectSP();
1043 DictionaryItemDescriptor &dict_item = m_children[idx];
1044 if (!dict_item.valobj_sp) {
1045 if (!m_pair_type.IsValid()) {
1046 TargetSP target_sp(m_backend.GetTargetSP());
1048 return ValueObjectSP();
1049 m_pair_type = GetLLDBNSPairType(target_sp);
1051 if (!m_pair_type.IsValid())
1052 return ValueObjectSP();
1054 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1056 if (m_ptr_size == 8) {
1057 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1058 *data_ptr = dict_item.key_ptr;
1059 *(data_ptr + 1) = dict_item.val_ptr;
1061 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1062 *data_ptr = dict_item.key_ptr;
1063 *(data_ptr + 1) = dict_item.val_ptr;
1066 StreamString idx_name;
1067 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1068 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1069 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1070 m_exe_ctx_ref, m_pair_type);
1072 return dict_item.valobj_sp;
1075 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(
1076 ValueObject &, Stream &, const TypeSummaryOptions &);
1078 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(
1079 ValueObject &, Stream &, const TypeSummaryOptions &);