Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / source / Plugins / Language / ObjC / NSDictionary.cpp
blob2e927eb8d8569188043299c9465e14efb6a38631
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-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include <mutex>
11 #include "clang/AST/DeclCXX.h"
13 #include "CFBasicHash.h"
14 #include "NSDictionary.h"
16 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
17 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
19 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Core/ValueObjectConstResult.h"
21 #include "lldb/DataFormatters/FormattersHelpers.h"
22 #include "lldb/Target/Language.h"
23 #include "lldb/Target/StackFrame.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Utility/DataBufferHeap.h"
26 #include "lldb/Utility/Endian.h"
27 #include "lldb/Utility/Status.h"
28 #include "lldb/Utility/Stream.h"
30 using namespace lldb;
31 using namespace lldb_private;
32 using namespace lldb_private::formatters;
34 NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
35 ConstString p)
36 : m_prefix(p) {}
38 bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(
39 ConstString class_name) {
40 return class_name.GetStringRef().startswith(m_prefix.GetStringRef());
43 NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)
44 : m_name(n) {}
46 bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match(
47 ConstString class_name) {
48 return (class_name == m_name);
51 NSDictionary_Additionals::AdditionalFormatters<
52 CXXFunctionSummaryFormat::Callback> &
53 NSDictionary_Additionals::GetAdditionalSummaries() {
54 static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map;
55 return g_map;
58 NSDictionary_Additionals::AdditionalFormatters<
59 CXXSyntheticChildren::CreateFrontEndCallback> &
60 NSDictionary_Additionals::GetAdditionalSynthetics() {
61 static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback>
62 g_map;
63 return g_map;
66 static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
67 CompilerType compiler_type;
68 TypeSystemClangSP scratch_ts_sp =
69 ScratchTypeSystemClang::GetForTarget(*target_sp);
71 if (!scratch_ts_sp)
72 return compiler_type;
74 static constexpr llvm::StringLiteral g_lldb_autogen_nspair("__lldb_autogen_nspair");
76 compiler_type = scratch_ts_sp->GetTypeForIdentifier<clang::CXXRecordDecl>(g_lldb_autogen_nspair);
78 if (!compiler_type) {
79 compiler_type = scratch_ts_sp->CreateRecordType(
80 nullptr, OptionalClangModuleID(), lldb::eAccessPublic,
81 g_lldb_autogen_nspair, clang::TTK_Struct, lldb::eLanguageTypeC);
83 if (compiler_type) {
84 TypeSystemClang::StartTagDeclarationDefinition(compiler_type);
85 CompilerType id_compiler_type =
86 scratch_ts_sp->GetBasicType(eBasicTypeObjCID);
87 TypeSystemClang::AddFieldToRecordType(
88 compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
89 TypeSystemClang::AddFieldToRecordType(
90 compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
91 TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
94 return compiler_type;
97 namespace lldb_private {
98 namespace formatters {
99 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
100 public:
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;
115 private:
116 struct DataDescriptor_32 {
117 uint32_t _used : 26;
118 uint32_t _szidx : 6;
121 struct DataDescriptor_64 {
122 uint64_t _used : 58;
123 uint32_t _szidx : 6;
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;
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;
142 class NSConstantDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
143 public:
144 NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
146 size_t CalculateNumChildren() override;
148 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
150 bool Update() override;
152 bool MightHaveChildren() override;
154 size_t GetIndexOfChildWithName(ConstString name) override;
156 private:
157 ExecutionContextRef m_exe_ctx_ref;
158 CompilerType m_pair_type;
159 uint8_t m_ptr_size = 8;
160 lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
161 unsigned int m_size = 0;
162 lldb::addr_t m_keys_ptr = LLDB_INVALID_ADDRESS;
163 lldb::addr_t m_objects_ptr = LLDB_INVALID_ADDRESS;
165 struct DictionaryItemDescriptor {
166 lldb::addr_t key_ptr;
167 lldb::addr_t val_ptr;
168 lldb::ValueObjectSP valobj_sp;
171 std::vector<DictionaryItemDescriptor> m_children;
174 class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
175 public:
176 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
178 size_t CalculateNumChildren() override;
180 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
182 bool Update() override;
184 bool MightHaveChildren() override;
186 size_t GetIndexOfChildWithName(ConstString name) override;
188 private:
189 struct DictionaryItemDescriptor {
190 lldb::addr_t key_ptr;
191 lldb::addr_t val_ptr;
192 lldb::ValueObjectSP valobj_sp;
195 ExecutionContextRef m_exe_ctx_ref;
196 uint8_t m_ptr_size = 8;
197 lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
199 CFBasicHash m_hashtable;
201 CompilerType m_pair_type;
202 std::vector<DictionaryItemDescriptor> m_children;
205 class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
206 public:
207 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
209 ~NSDictionary1SyntheticFrontEnd() override = default;
211 size_t CalculateNumChildren() override;
213 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
215 bool Update() override;
217 bool MightHaveChildren() override;
219 size_t GetIndexOfChildWithName(ConstString name) override;
221 private:
222 ValueObjectSP m_pair;
225 template <typename D32, typename D64>
226 class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
227 public:
228 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
230 ~GenericNSDictionaryMSyntheticFrontEnd() override;
232 size_t CalculateNumChildren() override;
234 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
236 bool Update() override;
238 bool MightHaveChildren() override;
240 size_t GetIndexOfChildWithName(ConstString name) override;
242 private:
243 struct DictionaryItemDescriptor {
244 lldb::addr_t key_ptr;
245 lldb::addr_t val_ptr;
246 lldb::ValueObjectSP valobj_sp;
249 ExecutionContextRef m_exe_ctx_ref;
250 uint8_t m_ptr_size = 8;
251 lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
252 D32 *m_data_32;
253 D64 *m_data_64;
254 CompilerType m_pair_type;
255 std::vector<DictionaryItemDescriptor> m_children;
258 namespace Foundation1100 {
259 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
260 public:
261 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
263 ~NSDictionaryMSyntheticFrontEnd() override;
265 size_t CalculateNumChildren() override;
267 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
269 bool Update() override;
271 bool MightHaveChildren() override;
273 size_t GetIndexOfChildWithName(ConstString name) override;
275 private:
276 struct DataDescriptor_32 {
277 uint32_t _used : 26;
278 uint32_t _kvo : 1;
279 uint32_t _size;
280 uint32_t _mutations;
281 uint32_t _objs_addr;
282 uint32_t _keys_addr;
285 struct DataDescriptor_64 {
286 uint64_t _used : 58;
287 uint32_t _kvo : 1;
288 uint64_t _size;
289 uint64_t _mutations;
290 uint64_t _objs_addr;
291 uint64_t _keys_addr;
294 struct DictionaryItemDescriptor {
295 lldb::addr_t key_ptr;
296 lldb::addr_t val_ptr;
297 lldb::ValueObjectSP valobj_sp;
300 ExecutionContextRef m_exe_ctx_ref;
301 uint8_t m_ptr_size = 8;
302 lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
303 DataDescriptor_32 *m_data_32 = nullptr;
304 DataDescriptor_64 *m_data_64 = nullptr;
305 CompilerType m_pair_type;
306 std::vector<DictionaryItemDescriptor> m_children;
310 namespace Foundation1428 {
311 namespace {
312 struct DataDescriptor_32 {
313 uint32_t _used : 26;
314 uint32_t _kvo : 1;
315 uint32_t _size;
316 uint32_t _buffer;
317 uint64_t GetSize() { return _size; }
320 struct DataDescriptor_64 {
321 uint64_t _used : 58;
322 uint32_t _kvo : 1;
323 uint64_t _size;
324 uint64_t _buffer;
325 uint64_t GetSize() { return _size; }
329 using NSDictionaryMSyntheticFrontEnd =
330 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
333 namespace Foundation1437 {
334 static const uint64_t NSDictionaryCapacities[] = {
335 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
336 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
337 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
338 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
339 111638519, 180634607, 292272623, 472907251
342 static const size_t NSDictionaryNumSizeBuckets =
343 sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
345 namespace {
346 struct DataDescriptor_32 {
347 uint32_t _buffer;
348 uint32_t _muts;
349 uint32_t _used : 25;
350 uint32_t _kvo : 1;
351 uint32_t _szidx : 6;
353 uint64_t GetSize() {
354 return (_szidx) >= NSDictionaryNumSizeBuckets ?
355 0 : NSDictionaryCapacities[_szidx];
359 struct DataDescriptor_64 {
360 uint64_t _buffer;
361 uint32_t _muts;
362 uint32_t _used : 25;
363 uint32_t _kvo : 1;
364 uint32_t _szidx : 6;
366 uint64_t GetSize() {
367 return (_szidx) >= NSDictionaryNumSizeBuckets ?
368 0 : NSDictionaryCapacities[_szidx];
371 } // namespace
373 using NSDictionaryMSyntheticFrontEnd =
374 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
376 template <typename DD>
377 uint64_t
378 __NSDictionaryMSize_Impl(lldb_private::Process &process,
379 lldb::addr_t valobj_addr, Status &error) {
380 const lldb::addr_t start_of_descriptor =
381 valobj_addr + process.GetAddressByteSize();
382 DD descriptor = DD();
383 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
384 error);
385 if (error.Fail()) {
386 return 0;
388 return descriptor._used;
391 uint64_t
392 __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
393 Status &error) {
394 if (process.GetAddressByteSize() == 4) {
395 return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
396 error);
397 } else {
398 return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
399 error);
404 } // namespace formatters
405 } // namespace lldb_private
407 template <bool name_entries>
408 bool lldb_private::formatters::NSDictionarySummaryProvider(
409 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
410 static constexpr llvm::StringLiteral g_TypeHint("NSDictionary");
411 ProcessSP process_sp = valobj.GetProcessSP();
412 if (!process_sp)
413 return false;
415 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
417 if (!runtime)
418 return false;
420 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
421 runtime->GetNonKVOClassDescriptor(valobj));
423 if (!descriptor || !descriptor->IsValid())
424 return false;
426 uint32_t ptr_size = process_sp->GetAddressByteSize();
427 bool is_64bit = (ptr_size == 8);
429 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
431 if (!valobj_addr)
432 return false;
434 uint64_t value = 0;
436 ConstString class_name(descriptor->GetClassName());
438 static const ConstString g_DictionaryI("__NSDictionaryI");
439 static const ConstString g_DictionaryM("__NSDictionaryM");
440 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
441 static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
442 static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");
443 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
444 static const ConstString g_Dictionary0("__NSDictionary0");
445 static const ConstString g_DictionaryCF("__CFDictionary");
446 static const ConstString g_DictionaryNSCF("__NSCFDictionary");
447 static const ConstString g_DictionaryCFRef("CFDictionaryRef");
448 static const ConstString g_ConstantDictionary("NSConstantDictionary");
450 if (class_name.IsEmpty())
451 return false;
453 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
454 Status error;
455 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
456 ptr_size, 0, error);
457 if (error.Fail())
458 return false;
460 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
461 } else if (class_name == g_ConstantDictionary) {
462 Status error;
463 value = process_sp->ReadUnsignedIntegerFromMemory(
464 valobj_addr + 2 * ptr_size, ptr_size, 0, error);
465 if (error.Fail())
466 return false;
467 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
468 class_name == g_DictionaryMFrozen) {
469 AppleObjCRuntime *apple_runtime =
470 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
471 Status error;
472 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
473 value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
474 error);
475 } else {
476 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
477 ptr_size, 0, error);
478 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
480 if (error.Fail())
481 return false;
482 } else if (class_name == g_Dictionary1) {
483 value = 1;
484 } else if (class_name == g_Dictionary0) {
485 value = 0;
486 } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
487 class_name == g_DictionaryCFRef) {
488 ExecutionContext exe_ctx(process_sp);
489 CFBasicHash cfbh;
490 if (!cfbh.Update(valobj_addr, exe_ctx))
491 return false;
492 value = cfbh.GetCount();
493 } else {
494 auto &map(NSDictionary_Additionals::GetAdditionalSummaries());
495 for (auto &candidate : map) {
496 if (candidate.first && candidate.first->Match(class_name))
497 return candidate.second(valobj, stream, options);
499 return false;
502 llvm::StringRef prefix, suffix;
503 if (Language *language = Language::FindPlugin(options.GetLanguage()))
504 std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
506 stream << prefix;
507 stream.Printf("%" PRIu64 " %s%s", value, "key/value pair",
508 value == 1 ? "" : "s");
509 stream << suffix;
510 return true;
513 SyntheticChildrenFrontEnd *
514 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
515 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
516 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
517 if (!process_sp)
518 return nullptr;
519 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
520 ObjCLanguageRuntime::Get(*process_sp));
521 if (!runtime)
522 return nullptr;
524 CompilerType valobj_type(valobj_sp->GetCompilerType());
525 Flags flags(valobj_type.GetTypeInfo());
527 if (flags.IsClear(eTypeIsPointer)) {
528 Status error;
529 valobj_sp = valobj_sp->AddressOf(error);
530 if (error.Fail() || !valobj_sp)
531 return nullptr;
534 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
535 runtime->GetClassDescriptor(*valobj_sp));
537 if (!descriptor || !descriptor->IsValid())
538 return nullptr;
540 ConstString class_name(descriptor->GetClassName());
542 static const ConstString g_DictionaryI("__NSDictionaryI");
543 static const ConstString g_DictionaryM("__NSDictionaryM");
544 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
545 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
546 static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");
547 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
548 static const ConstString g_Dictionary0("__NSDictionary0");
549 static const ConstString g_DictionaryCF("__CFDictionary");
550 static const ConstString g_DictionaryNSCF("__NSCFDictionary");
551 static const ConstString g_DictionaryCFRef("CFDictionaryRef");
552 static const ConstString g_ConstantDictionary("NSConstantDictionary");
554 if (class_name.IsEmpty())
555 return nullptr;
557 if (class_name == g_DictionaryI) {
558 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
559 } else if (class_name == g_ConstantDictionary) {
560 return (new NSConstantDictionarySyntheticFrontEnd(valobj_sp));
561 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) {
562 if (runtime->GetFoundationVersion() >= 1437) {
563 return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
564 } else if (runtime->GetFoundationVersion() >= 1428) {
565 return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));
566 } else {
567 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
569 } else if (class_name == g_DictionaryMLegacy) {
570 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
571 } else if (class_name == g_Dictionary1) {
572 return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
573 } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
574 class_name == g_DictionaryCFRef) {
575 return (new NSCFDictionarySyntheticFrontEnd(valobj_sp));
576 } else {
577 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());
578 for (auto &candidate : map) {
579 if (candidate.first && candidate.first->Match((class_name)))
580 return candidate.second(synth, valobj_sp);
584 return nullptr;
587 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
588 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
589 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
591 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
592 ~NSDictionaryISyntheticFrontEnd() {
593 delete m_data_32;
594 m_data_32 = nullptr;
595 delete m_data_64;
596 m_data_64 = nullptr;
599 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
600 GetIndexOfChildWithName(ConstString name) {
601 const char *item_name = name.GetCString();
602 uint32_t idx = ExtractIndexFromString(item_name);
603 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
604 return UINT32_MAX;
605 return idx;
608 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
609 CalculateNumChildren() {
610 if (!m_data_32 && !m_data_64)
611 return 0;
612 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
615 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
616 m_children.clear();
617 delete m_data_32;
618 m_data_32 = nullptr;
619 delete m_data_64;
620 m_data_64 = nullptr;
621 m_ptr_size = 0;
622 ValueObjectSP valobj_sp = m_backend.GetSP();
623 if (!valobj_sp)
624 return false;
625 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
626 Status error;
627 error.Clear();
628 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
629 if (!process_sp)
630 return false;
631 m_ptr_size = process_sp->GetAddressByteSize();
632 m_order = process_sp->GetByteOrder();
633 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
634 if (m_ptr_size == 4) {
635 m_data_32 = new DataDescriptor_32();
636 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
637 error);
638 } else {
639 m_data_64 = new DataDescriptor_64();
640 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
641 error);
643 if (error.Fail())
644 return false;
645 m_data_ptr = data_location + m_ptr_size;
646 return false;
649 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
650 MightHaveChildren() {
651 return true;
654 lldb::ValueObjectSP
655 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
656 size_t idx) {
657 uint32_t num_children = CalculateNumChildren();
659 if (idx >= num_children)
660 return lldb::ValueObjectSP();
662 if (m_children.empty()) {
663 // do the scan phase
664 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
666 uint32_t tries = 0;
667 uint32_t test_idx = 0;
669 while (tries < num_children) {
670 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
671 val_at_idx = key_at_idx + m_ptr_size;
672 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
673 if (!process_sp)
674 return lldb::ValueObjectSP();
675 Status error;
676 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
677 if (error.Fail())
678 return lldb::ValueObjectSP();
679 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
680 if (error.Fail())
681 return lldb::ValueObjectSP();
683 test_idx++;
685 if (!key_at_idx || !val_at_idx)
686 continue;
687 tries++;
689 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
690 lldb::ValueObjectSP()};
692 m_children.push_back(descriptor);
696 if (idx >= m_children.size()) // should never happen
697 return lldb::ValueObjectSP();
699 DictionaryItemDescriptor &dict_item = m_children[idx];
700 if (!dict_item.valobj_sp) {
701 if (!m_pair_type.IsValid()) {
702 TargetSP target_sp(m_backend.GetTargetSP());
703 if (!target_sp)
704 return ValueObjectSP();
705 m_pair_type = GetLLDBNSPairType(target_sp);
707 if (!m_pair_type.IsValid())
708 return ValueObjectSP();
710 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
712 if (m_ptr_size == 8) {
713 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
714 *data_ptr = dict_item.key_ptr;
715 *(data_ptr + 1) = dict_item.val_ptr;
716 } else {
717 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
718 *data_ptr = dict_item.key_ptr;
719 *(data_ptr + 1) = dict_item.val_ptr;
722 StreamString idx_name;
723 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
724 DataExtractor data(buffer_sp, m_order, m_ptr_size);
725 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
726 m_exe_ctx_ref, m_pair_type);
728 return dict_item.valobj_sp;
731 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
732 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
733 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),
734 m_pair_type() {}
736 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
737 GetIndexOfChildWithName(ConstString name) {
738 const char *item_name = name.GetCString();
739 const uint32_t idx = ExtractIndexFromString(item_name);
740 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
741 return UINT32_MAX;
742 return idx;
745 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
746 CalculateNumChildren() {
747 if (!m_hashtable.IsValid())
748 return 0;
749 return m_hashtable.GetCount();
752 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {
753 m_children.clear();
754 ValueObjectSP valobj_sp = m_backend.GetSP();
755 m_ptr_size = 0;
756 if (!valobj_sp)
757 return false;
758 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
760 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
761 if (!process_sp)
762 return false;
763 m_ptr_size = process_sp->GetAddressByteSize();
764 m_order = process_sp->GetByteOrder();
765 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref);
768 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
769 MightHaveChildren() {
770 return true;
773 lldb::ValueObjectSP
774 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
775 size_t idx) {
776 lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer();
777 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
779 const uint32_t num_children = CalculateNumChildren();
781 if (idx >= num_children)
782 return lldb::ValueObjectSP();
784 if (m_children.empty()) {
785 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
786 if (!process_sp)
787 return lldb::ValueObjectSP();
789 Status error;
790 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
792 uint32_t tries = 0;
793 uint32_t test_idx = 0;
795 // Iterate over inferior memory, reading key/value pointers by shifting each
796 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
797 // fails, otherwise, continue until the number of tries matches the number
798 // of childen.
799 while (tries < num_children) {
800 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
801 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
803 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
804 if (error.Fail())
805 return lldb::ValueObjectSP();
806 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
807 if (error.Fail())
808 return lldb::ValueObjectSP();
810 test_idx++;
812 if (!key_at_idx || !val_at_idx)
813 continue;
814 tries++;
816 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
817 lldb::ValueObjectSP()};
819 m_children.push_back(descriptor);
823 if (idx >= m_children.size()) // should never happen
824 return lldb::ValueObjectSP();
826 DictionaryItemDescriptor &dict_item = m_children[idx];
827 if (!dict_item.valobj_sp) {
828 if (!m_pair_type.IsValid()) {
829 TargetSP target_sp(m_backend.GetTargetSP());
830 if (!target_sp)
831 return ValueObjectSP();
832 m_pair_type = GetLLDBNSPairType(target_sp);
834 if (!m_pair_type.IsValid())
835 return ValueObjectSP();
837 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
839 switch (m_ptr_size) {
840 case 0: // architecture has no clue - fail
841 return lldb::ValueObjectSP();
842 case 4: {
843 uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes());
844 *data_ptr = dict_item.key_ptr;
845 *(data_ptr + 1) = dict_item.val_ptr;
846 } break;
847 case 8: {
848 uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes());
849 *data_ptr = dict_item.key_ptr;
850 *(data_ptr + 1) = dict_item.val_ptr;
851 } break;
852 default:
853 lldbassert(false && "pointer size is not 4 nor 8");
856 StreamString idx_name;
857 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
858 DataExtractor data(buffer_sp, m_order, m_ptr_size);
859 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
860 m_exe_ctx_ref, m_pair_type);
862 return dict_item.valobj_sp;
865 lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
866 NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
867 : SyntheticChildrenFrontEnd(*valobj_sp) {}
869 size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
870 GetIndexOfChildWithName(ConstString name) {
871 const char *item_name = name.GetCString();
872 uint32_t idx = ExtractIndexFromString(item_name);
873 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
874 return UINT32_MAX;
875 return idx;
878 size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
879 CalculateNumChildren() {
880 return m_size;
883 bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() {
884 ValueObjectSP valobj_sp = m_backend.GetSP();
885 if (!valobj_sp)
886 return false;
887 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
888 Status error;
889 error.Clear();
890 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
891 if (!process_sp)
892 return false;
893 m_ptr_size = process_sp->GetAddressByteSize();
894 m_order = process_sp->GetByteOrder();
895 uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0);
896 m_size = process_sp->ReadUnsignedIntegerFromMemory(
897 valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error);
898 if (error.Fail())
899 return false;
900 m_keys_ptr =
901 process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size, error);
902 if (error.Fail())
903 return false;
904 m_objects_ptr =
905 process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size, error);
906 return !error.Fail();
909 bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
910 MightHaveChildren() {
911 return true;
914 lldb::ValueObjectSP lldb_private::formatters::
915 NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(size_t idx) {
916 uint32_t num_children = CalculateNumChildren();
918 if (idx >= num_children)
919 return lldb::ValueObjectSP();
921 if (m_children.empty()) {
922 // do the scan phase
923 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
924 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
925 if (!process_sp)
926 return lldb::ValueObjectSP();
928 for (unsigned int child = 0; child < num_children; ++child) {
929 Status error;
930 key_at_idx = process_sp->ReadPointerFromMemory(
931 m_keys_ptr + child * m_ptr_size, error);
932 if (error.Fail())
933 return lldb::ValueObjectSP();
934 val_at_idx = process_sp->ReadPointerFromMemory(
935 m_objects_ptr + child * m_ptr_size, error);
936 if (error.Fail())
937 return lldb::ValueObjectSP();
938 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
939 lldb::ValueObjectSP()};
940 m_children.push_back(descriptor);
944 if (idx >= m_children.size()) // should never happen
945 return lldb::ValueObjectSP();
947 DictionaryItemDescriptor &dict_item = m_children[idx];
948 if (!dict_item.valobj_sp) {
949 if (!m_pair_type.IsValid()) {
950 TargetSP target_sp(m_backend.GetTargetSP());
951 if (!target_sp)
952 return ValueObjectSP();
953 m_pair_type = GetLLDBNSPairType(target_sp);
955 if (!m_pair_type.IsValid())
956 return ValueObjectSP();
958 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
960 if (m_ptr_size == 8) {
961 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
962 *data_ptr = dict_item.key_ptr;
963 *(data_ptr + 1) = dict_item.val_ptr;
964 } else {
965 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
966 *data_ptr = dict_item.key_ptr;
967 *(data_ptr + 1) = dict_item.val_ptr;
970 StreamString idx_name;
971 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
972 DataExtractor data(buffer_sp, m_order, m_ptr_size);
973 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
974 m_exe_ctx_ref, m_pair_type);
976 return dict_item.valobj_sp;
979 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
980 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
981 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
983 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
984 GetIndexOfChildWithName(ConstString name) {
985 static const ConstString g_zero("[0]");
986 return name == g_zero ? 0 : UINT32_MAX;
989 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
990 CalculateNumChildren() {
991 return 1;
994 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
995 m_pair.reset();
996 return false;
999 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
1000 MightHaveChildren() {
1001 return true;
1004 lldb::ValueObjectSP
1005 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
1006 size_t idx) {
1007 if (idx != 0)
1008 return lldb::ValueObjectSP();
1010 if (m_pair.get())
1011 return m_pair;
1013 auto process_sp(m_backend.GetProcessSP());
1014 if (!process_sp)
1015 return nullptr;
1017 auto ptr_size = process_sp->GetAddressByteSize();
1019 lldb::addr_t key_ptr =
1020 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
1021 lldb::addr_t value_ptr = key_ptr + ptr_size;
1023 Status error;
1025 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
1026 if (error.Fail())
1027 return nullptr;
1028 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
1029 if (error.Fail())
1030 return nullptr;
1032 auto pair_type =
1033 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
1035 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
1037 if (ptr_size == 8) {
1038 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1039 *data_ptr = key_at_idx;
1040 *(data_ptr + 1) = value_at_idx;
1041 } else {
1042 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1043 *data_ptr = key_at_idx;
1044 *(data_ptr + 1) = value_at_idx;
1047 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
1048 m_pair = CreateValueObjectFromData(
1049 "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
1051 return m_pair;
1054 template <typename D32, typename D64>
1055 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32, D64>::
1056 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
1057 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
1058 m_data_32(nullptr), m_data_64(nullptr), m_pair_type() {}
1060 template <typename D32, typename D64>
1061 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
1062 ~GenericNSDictionaryMSyntheticFrontEnd<D32,D64>() {
1063 delete m_data_32;
1064 m_data_32 = nullptr;
1065 delete m_data_64;
1066 m_data_64 = nullptr;
1069 template <typename D32, typename D64>
1070 size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
1071 D32, D64>::GetIndexOfChildWithName(ConstString name) {
1072 const char *item_name = name.GetCString();
1073 uint32_t idx = ExtractIndexFromString(item_name);
1074 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1075 return UINT32_MAX;
1076 return idx;
1079 template <typename D32, typename D64>
1080 size_t
1081 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() {
1082 if (!m_data_32 && !m_data_64)
1083 return 0;
1084 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1087 template <typename D32, typename D64>
1088 bool
1089 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
1090 Update() {
1091 m_children.clear();
1092 ValueObjectSP valobj_sp = m_backend.GetSP();
1093 m_ptr_size = 0;
1094 delete m_data_32;
1095 m_data_32 = nullptr;
1096 delete m_data_64;
1097 m_data_64 = nullptr;
1098 if (!valobj_sp)
1099 return false;
1100 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1101 Status error;
1102 error.Clear();
1103 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1104 if (!process_sp)
1105 return false;
1106 m_ptr_size = process_sp->GetAddressByteSize();
1107 m_order = process_sp->GetByteOrder();
1108 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1109 if (m_ptr_size == 4) {
1110 m_data_32 = new D32();
1111 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
1112 error);
1113 } else {
1114 m_data_64 = new D64();
1115 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
1116 error);
1119 return error.Success();
1122 template <typename D32, typename D64>
1123 bool
1124 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
1125 MightHaveChildren() {
1126 return true;
1129 template <typename D32, typename D64>
1130 lldb::ValueObjectSP
1131 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
1132 D32, D64>::GetChildAtIndex(size_t idx) {
1133 lldb::addr_t m_keys_ptr;
1134 lldb::addr_t m_values_ptr;
1135 if (m_data_32) {
1136 uint32_t size = m_data_32->GetSize();
1137 m_keys_ptr = m_data_32->_buffer;
1138 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
1139 } else {
1140 uint32_t size = m_data_64->GetSize();
1141 m_keys_ptr = m_data_64->_buffer;
1142 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
1145 uint32_t num_children = CalculateNumChildren();
1147 if (idx >= num_children)
1148 return lldb::ValueObjectSP();
1150 if (m_children.empty()) {
1151 // do the scan phase
1152 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1154 uint32_t tries = 0;
1155 uint32_t test_idx = 0;
1157 while (tries < num_children) {
1158 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1159 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1161 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1162 if (!process_sp)
1163 return lldb::ValueObjectSP();
1164 Status error;
1165 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1166 if (error.Fail())
1167 return lldb::ValueObjectSP();
1168 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1169 if (error.Fail())
1170 return lldb::ValueObjectSP();
1172 test_idx++;
1174 if (!key_at_idx || !val_at_idx)
1175 continue;
1176 tries++;
1178 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1179 lldb::ValueObjectSP()};
1181 m_children.push_back(descriptor);
1185 if (idx >= m_children.size()) // should never happen
1186 return lldb::ValueObjectSP();
1188 DictionaryItemDescriptor &dict_item = m_children[idx];
1189 if (!dict_item.valobj_sp) {
1190 if (!m_pair_type.IsValid()) {
1191 TargetSP target_sp(m_backend.GetTargetSP());
1192 if (!target_sp)
1193 return ValueObjectSP();
1194 m_pair_type = GetLLDBNSPairType(target_sp);
1196 if (!m_pair_type.IsValid())
1197 return ValueObjectSP();
1199 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1201 if (m_ptr_size == 8) {
1202 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1203 *data_ptr = dict_item.key_ptr;
1204 *(data_ptr + 1) = dict_item.val_ptr;
1205 } else {
1206 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1207 *data_ptr = dict_item.key_ptr;
1208 *(data_ptr + 1) = dict_item.val_ptr;
1211 StreamString idx_name;
1212 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1213 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1214 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1215 m_exe_ctx_ref, m_pair_type);
1217 return dict_item.valobj_sp;
1220 lldb_private::formatters::Foundation1100::NSDictionaryMSyntheticFrontEnd::
1221 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
1222 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
1224 lldb_private::formatters::Foundation1100::
1225 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {
1226 delete m_data_32;
1227 m_data_32 = nullptr;
1228 delete m_data_64;
1229 m_data_64 = nullptr;
1232 size_t
1233 lldb_private::formatters::Foundation1100::
1234 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
1235 const char *item_name = name.GetCString();
1236 uint32_t idx = ExtractIndexFromString(item_name);
1237 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1238 return UINT32_MAX;
1239 return idx;
1242 size_t
1243 lldb_private::formatters::Foundation1100::
1244 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
1245 if (!m_data_32 && !m_data_64)
1246 return 0;
1247 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1250 bool
1251 lldb_private::formatters::Foundation1100::
1252 NSDictionaryMSyntheticFrontEnd::Update() {
1253 m_children.clear();
1254 ValueObjectSP valobj_sp = m_backend.GetSP();
1255 m_ptr_size = 0;
1256 delete m_data_32;
1257 m_data_32 = nullptr;
1258 delete m_data_64;
1259 m_data_64 = nullptr;
1260 if (!valobj_sp)
1261 return false;
1262 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1263 Status error;
1264 error.Clear();
1265 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1266 if (!process_sp)
1267 return false;
1268 m_ptr_size = process_sp->GetAddressByteSize();
1269 m_order = process_sp->GetByteOrder();
1270 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1271 if (m_ptr_size == 4) {
1272 m_data_32 = new DataDescriptor_32();
1273 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
1274 error);
1275 } else {
1276 m_data_64 = new DataDescriptor_64();
1277 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
1278 error);
1281 return error.Success();
1284 bool
1285 lldb_private::formatters::Foundation1100::
1286 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
1287 return true;
1290 lldb::ValueObjectSP
1291 lldb_private::formatters::Foundation1100::
1292 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
1293 lldb::addr_t m_keys_ptr =
1294 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
1295 lldb::addr_t m_values_ptr =
1296 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
1298 uint32_t num_children = CalculateNumChildren();
1300 if (idx >= num_children)
1301 return lldb::ValueObjectSP();
1303 if (m_children.empty()) {
1304 // do the scan phase
1305 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1307 uint32_t tries = 0;
1308 uint32_t test_idx = 0;
1310 while (tries < num_children) {
1311 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1312 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1314 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1315 if (!process_sp)
1316 return lldb::ValueObjectSP();
1317 Status error;
1318 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1319 if (error.Fail())
1320 return lldb::ValueObjectSP();
1321 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1322 if (error.Fail())
1323 return lldb::ValueObjectSP();
1325 test_idx++;
1327 if (!key_at_idx || !val_at_idx)
1328 continue;
1329 tries++;
1331 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1332 lldb::ValueObjectSP()};
1334 m_children.push_back(descriptor);
1338 if (idx >= m_children.size()) // should never happen
1339 return lldb::ValueObjectSP();
1341 DictionaryItemDescriptor &dict_item = m_children[idx];
1342 if (!dict_item.valobj_sp) {
1343 if (!m_pair_type.IsValid()) {
1344 TargetSP target_sp(m_backend.GetTargetSP());
1345 if (!target_sp)
1346 return ValueObjectSP();
1347 m_pair_type = GetLLDBNSPairType(target_sp);
1349 if (!m_pair_type.IsValid())
1350 return ValueObjectSP();
1352 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1354 if (m_ptr_size == 8) {
1355 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1356 *data_ptr = dict_item.key_ptr;
1357 *(data_ptr + 1) = dict_item.val_ptr;
1358 } else {
1359 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1360 *data_ptr = dict_item.key_ptr;
1361 *(data_ptr + 1) = dict_item.val_ptr;
1364 StreamString idx_name;
1365 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1366 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1367 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1368 m_exe_ctx_ref, m_pair_type);
1370 return dict_item.valobj_sp;
1373 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(
1374 ValueObject &, Stream &, const TypeSummaryOptions &);
1376 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(
1377 ValueObject &, Stream &, const TypeSummaryOptions &);