1 //===-- NSDictionary.cpp --------------------------------------------------===//
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 "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"
31 using namespace lldb_private
;
32 using namespace lldb_private::formatters
;
34 NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
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
)
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
;
58 NSDictionary_Additionals::AdditionalFormatters
<
59 CXXSyntheticChildren::CreateFrontEndCallback
> &
60 NSDictionary_Additionals::GetAdditionalSynthetics() {
61 static AdditionalFormatters
<CXXSyntheticChildren::CreateFrontEndCallback
>
66 static CompilerType
GetLLDBNSPairType(TargetSP target_sp
) {
67 CompilerType compiler_type
;
68 TypeSystemClangSP scratch_ts_sp
=
69 ScratchTypeSystemClang::GetForTarget(*target_sp
);
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
);
79 compiler_type
= scratch_ts_sp
->CreateRecordType(
80 nullptr, OptionalClangModuleID(), lldb::eAccessPublic
,
81 g_lldb_autogen_nspair
, clang::TTK_Struct
, lldb::eLanguageTypeC
);
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
);
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
;
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
{
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
;
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
{
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
;
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
{
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
;
222 ValueObjectSP m_pair
;
225 template <typename D32
, typename D64
>
226 class GenericNSDictionaryMSyntheticFrontEnd
: public SyntheticChildrenFrontEnd
{
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
;
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
;
254 CompilerType m_pair_type
;
255 std::vector
<DictionaryItemDescriptor
> m_children
;
258 namespace Foundation1100
{
259 class NSDictionaryMSyntheticFrontEnd
: public SyntheticChildrenFrontEnd
{
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
;
276 struct DataDescriptor_32
{
285 struct DataDescriptor_64
{
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
{
312 struct DataDescriptor_32
{
317 uint64_t GetSize() { return _size
; }
320 struct DataDescriptor_64
{
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);
346 struct DataDescriptor_32
{
354 return (_szidx
) >= NSDictionaryNumSizeBuckets
?
355 0 : NSDictionaryCapacities
[_szidx
];
359 struct DataDescriptor_64
{
367 return (_szidx
) >= NSDictionaryNumSizeBuckets
?
368 0 : NSDictionaryCapacities
[_szidx
];
373 using NSDictionaryMSyntheticFrontEnd
=
374 GenericNSDictionaryMSyntheticFrontEnd
<DataDescriptor_32
, DataDescriptor_64
>;
376 template <typename DD
>
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
),
388 return descriptor
._used
;
392 __NSDictionaryMSize(lldb_private::Process
&process
, lldb::addr_t valobj_addr
,
394 if (process
.GetAddressByteSize() == 4) {
395 return __NSDictionaryMSize_Impl
<DataDescriptor_32
>(process
, valobj_addr
,
398 return __NSDictionaryMSize_Impl
<DataDescriptor_64
>(process
, valobj_addr
,
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();
415 ObjCLanguageRuntime
*runtime
= ObjCLanguageRuntime::Get(*process_sp
);
420 ObjCLanguageRuntime::ClassDescriptorSP
descriptor(
421 runtime
->GetNonKVOClassDescriptor(valobj
));
423 if (!descriptor
|| !descriptor
->IsValid())
426 uint32_t ptr_size
= process_sp
->GetAddressByteSize();
427 bool is_64bit
= (ptr_size
== 8);
429 lldb::addr_t valobj_addr
= valobj
.GetValueAsUnsigned(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())
453 if (class_name
== g_DictionaryI
|| class_name
== g_DictionaryMImmutable
) {
455 value
= process_sp
->ReadUnsignedIntegerFromMemory(valobj_addr
+ ptr_size
,
460 value
&= (is_64bit
? ~0xFC00000000000000UL
: ~0xFC000000U
);
461 } else if (class_name
== g_ConstantDictionary
) {
463 value
= process_sp
->ReadUnsignedIntegerFromMemory(
464 valobj_addr
+ 2 * ptr_size
, ptr_size
, 0, error
);
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
);
472 if (apple_runtime
&& apple_runtime
->GetFoundationVersion() >= 1437) {
473 value
= Foundation1437::__NSDictionaryMSize(*process_sp
, valobj_addr
,
476 value
= process_sp
->ReadUnsignedIntegerFromMemory(valobj_addr
+ ptr_size
,
478 value
&= (is_64bit
? ~0xFC00000000000000UL
: ~0xFC000000U
);
482 } else if (class_name
== g_Dictionary1
) {
484 } else if (class_name
== g_Dictionary0
) {
486 } else if (class_name
== g_DictionaryCF
|| class_name
== g_DictionaryNSCF
||
487 class_name
== g_DictionaryCFRef
) {
488 ExecutionContext
exe_ctx(process_sp
);
490 if (!cfbh
.Update(valobj_addr
, exe_ctx
))
492 value
= cfbh
.GetCount();
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
);
502 llvm::StringRef prefix
, suffix
;
503 if (Language
*language
= Language::FindPlugin(options
.GetLanguage()))
504 std::tie(prefix
, suffix
) = language
->GetFormatterPrefixSuffix(g_TypeHint
);
507 stream
.Printf("%" PRIu64
" %s%s", value
, "key/value pair",
508 value
== 1 ? "" : "s");
513 SyntheticChildrenFrontEnd
*
514 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
515 CXXSyntheticChildren
*synth
, lldb::ValueObjectSP valobj_sp
) {
516 lldb::ProcessSP
process_sp(valobj_sp
->GetProcessSP());
519 AppleObjCRuntime
*runtime
= llvm::dyn_cast_or_null
<AppleObjCRuntime
>(
520 ObjCLanguageRuntime::Get(*process_sp
));
524 CompilerType
valobj_type(valobj_sp
->GetCompilerType());
525 Flags
flags(valobj_type
.GetTypeInfo());
527 if (flags
.IsClear(eTypeIsPointer
)) {
529 valobj_sp
= valobj_sp
->AddressOf(error
);
530 if (error
.Fail() || !valobj_sp
)
534 ObjCLanguageRuntime::ClassDescriptorSP
descriptor(
535 runtime
->GetClassDescriptor(*valobj_sp
));
537 if (!descriptor
|| !descriptor
->IsValid())
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())
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
));
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
));
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
);
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() {
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())
608 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
609 CalculateNumChildren() {
610 if (!m_data_32
&& !m_data_64
)
612 return (m_data_32
? m_data_32
->_used
: m_data_64
->_used
);
615 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
622 ValueObjectSP valobj_sp
= m_backend
.GetSP();
625 m_exe_ctx_ref
= valobj_sp
->GetExecutionContextRef();
628 lldb::ProcessSP
process_sp(valobj_sp
->GetProcessSP());
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
),
639 m_data_64
= new DataDescriptor_64();
640 process_sp
->ReadMemory(data_location
, m_data_64
, sizeof(DataDescriptor_64
),
645 m_data_ptr
= data_location
+ m_ptr_size
;
649 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
650 MightHaveChildren() {
655 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
657 uint32_t num_children
= CalculateNumChildren();
659 if (idx
>= num_children
)
660 return lldb::ValueObjectSP();
662 if (m_children
.empty()) {
664 lldb::addr_t key_at_idx
= 0, val_at_idx
= 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();
674 return lldb::ValueObjectSP();
676 key_at_idx
= process_sp
->ReadPointerFromMemory(key_at_idx
, error
);
678 return lldb::ValueObjectSP();
679 val_at_idx
= process_sp
->ReadPointerFromMemory(val_at_idx
, error
);
681 return lldb::ValueObjectSP();
685 if (!key_at_idx
|| !val_at_idx
)
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());
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
;
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(),
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())
745 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
746 CalculateNumChildren() {
747 if (!m_hashtable
.IsValid())
749 return m_hashtable
.GetCount();
752 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {
754 ValueObjectSP valobj_sp
= m_backend
.GetSP();
758 m_exe_ctx_ref
= valobj_sp
->GetExecutionContextRef();
760 lldb::ProcessSP
process_sp(valobj_sp
->GetProcessSP());
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() {
774 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
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();
787 return lldb::ValueObjectSP();
790 lldb::addr_t key_at_idx
= 0, val_at_idx
= 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
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
);
805 return lldb::ValueObjectSP();
806 val_at_idx
= process_sp
->ReadPointerFromMemory(val_at_idx
, error
);
808 return lldb::ValueObjectSP();
812 if (!key_at_idx
|| !val_at_idx
)
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());
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();
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
;
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
;
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())
878 size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
879 CalculateNumChildren() {
883 bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() {
884 ValueObjectSP valobj_sp
= m_backend
.GetSP();
887 m_exe_ctx_ref
= valobj_sp
->GetExecutionContextRef();
890 lldb::ProcessSP
process_sp(valobj_sp
->GetProcessSP());
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
);
901 process_sp
->ReadPointerFromMemory(valobj_addr
+ 3 * m_ptr_size
, error
);
905 process_sp
->ReadPointerFromMemory(valobj_addr
+ 4 * m_ptr_size
, error
);
906 return !error
.Fail();
909 bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
910 MightHaveChildren() {
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()) {
923 lldb::addr_t key_at_idx
= 0, val_at_idx
= 0;
924 ProcessSP process_sp
= m_exe_ctx_ref
.GetProcessSP();
926 return lldb::ValueObjectSP();
928 for (unsigned int child
= 0; child
< num_children
; ++child
) {
930 key_at_idx
= process_sp
->ReadPointerFromMemory(
931 m_keys_ptr
+ child
* m_ptr_size
, error
);
933 return lldb::ValueObjectSP();
934 val_at_idx
= process_sp
->ReadPointerFromMemory(
935 m_objects_ptr
+ child
* m_ptr_size
, error
);
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());
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
;
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() {
994 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
999 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
1000 MightHaveChildren() {
1005 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
1008 return lldb::ValueObjectSP();
1013 auto process_sp(m_backend
.GetProcessSP());
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
;
1025 lldb::addr_t value_at_idx
= process_sp
->ReadPointerFromMemory(key_ptr
, error
);
1028 lldb::addr_t key_at_idx
= process_sp
->ReadPointerFromMemory(value_ptr
, error
);
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
;
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
);
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
>() {
1064 m_data_32
= nullptr;
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())
1079 template <typename D32
, typename D64
>
1081 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd
<D32
,D64
>::CalculateNumChildren() {
1082 if (!m_data_32
&& !m_data_64
)
1084 return (m_data_32
? m_data_32
->_used
: m_data_64
->_used
);
1087 template <typename D32
, typename D64
>
1089 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd
<D32
,D64
>::
1092 ValueObjectSP valobj_sp
= m_backend
.GetSP();
1095 m_data_32
= nullptr;
1097 m_data_64
= nullptr;
1100 m_exe_ctx_ref
= valobj_sp
->GetExecutionContextRef();
1103 lldb::ProcessSP
process_sp(valobj_sp
->GetProcessSP());
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
),
1114 m_data_64
= new D64();
1115 process_sp
->ReadMemory(data_location
, m_data_64
, sizeof(D64
),
1119 return error
.Success();
1122 template <typename D32
, typename D64
>
1124 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd
<D32
,D64
>::
1125 MightHaveChildren() {
1129 template <typename D32
, typename D64
>
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
;
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
);
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;
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();
1163 return lldb::ValueObjectSP();
1165 key_at_idx
= process_sp
->ReadPointerFromMemory(key_at_idx
, error
);
1167 return lldb::ValueObjectSP();
1168 val_at_idx
= process_sp
->ReadPointerFromMemory(val_at_idx
, error
);
1170 return lldb::ValueObjectSP();
1174 if (!key_at_idx
|| !val_at_idx
)
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());
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
;
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() {
1227 m_data_32
= nullptr;
1229 m_data_64
= nullptr;
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())
1243 lldb_private::formatters::Foundation1100::
1244 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
1245 if (!m_data_32
&& !m_data_64
)
1247 return (m_data_32
? m_data_32
->_used
: m_data_64
->_used
);
1251 lldb_private::formatters::Foundation1100::
1252 NSDictionaryMSyntheticFrontEnd::Update() {
1254 ValueObjectSP valobj_sp
= m_backend
.GetSP();
1257 m_data_32
= nullptr;
1259 m_data_64
= nullptr;
1262 m_exe_ctx_ref
= valobj_sp
->GetExecutionContextRef();
1265 lldb::ProcessSP
process_sp(valobj_sp
->GetProcessSP());
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
),
1276 m_data_64
= new DataDescriptor_64();
1277 process_sp
->ReadMemory(data_location
, m_data_64
, sizeof(DataDescriptor_64
),
1281 return error
.Success();
1285 lldb_private::formatters::Foundation1100::
1286 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
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;
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();
1316 return lldb::ValueObjectSP();
1318 key_at_idx
= process_sp
->ReadPointerFromMemory(key_at_idx
, error
);
1320 return lldb::ValueObjectSP();
1321 val_at_idx
= process_sp
->ReadPointerFromMemory(val_at_idx
, error
);
1323 return lldb::ValueObjectSP();
1327 if (!key_at_idx
|| !val_at_idx
)
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());
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
;
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
&);