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 //===----------------------------------------------------------------------===//
8
9 #include <mutex>
10
11 #include "clang/AST/DeclCXX.h"
12
13 #include "CFBasicHash.h"
14 #include "NSDictionary.h"
15
16 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
17 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
18
19 #include "lldb/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"
29
30 using namespace lldb;
31 using namespace lldb_private;
32 using namespace lldb_private::formatters;
33
Prefix(ConstString p)34 NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
35 ConstString p)
36 : m_prefix(p) {}
37
Match(ConstString class_name)38 bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(
39 ConstString class_name) {
40 return class_name.GetStringRef().startswith(m_prefix.GetStringRef());
41 }
42
Full(ConstString n)43 NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)
44 : m_name(n) {}
45
Match(ConstString class_name)46 bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match(
47 ConstString class_name) {
48 return (class_name == m_name);
49 }
50
51 NSDictionary_Additionals::AdditionalFormatters<
52 CXXFunctionSummaryFormat::Callback> &
GetAdditionalSummaries()53 NSDictionary_Additionals::GetAdditionalSummaries() {
54 static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map;
55 return g_map;
56 }
57
58 NSDictionary_Additionals::AdditionalFormatters<
59 CXXSyntheticChildren::CreateFrontEndCallback> &
GetAdditionalSynthetics()60 NSDictionary_Additionals::GetAdditionalSynthetics() {
61 static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback>
62 g_map;
63 return g_map;
64 }
65
GetLLDBNSPairType(TargetSP target_sp)66 static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
67 CompilerType compiler_type;
68
69 TypeSystemClang *target_ast_context =
70 ScratchTypeSystemClang::GetForTarget(*target_sp);
71
72 if (target_ast_context) {
73 ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
74
75 compiler_type =
76 target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(
77 g___lldb_autogen_nspair);
78
79 if (!compiler_type) {
80 compiler_type = target_ast_context->CreateRecordType(
81 nullptr, OptionalClangModuleID(), lldb::eAccessPublic,
82 g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct,
83 lldb::eLanguageTypeC);
84
85 if (compiler_type) {
86 TypeSystemClang::StartTagDeclarationDefinition(compiler_type);
87 CompilerType id_compiler_type =
88 target_ast_context->GetBasicType(eBasicTypeObjCID);
89 TypeSystemClang::AddFieldToRecordType(
90 compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
91 TypeSystemClang::AddFieldToRecordType(
92 compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
93 TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
94 }
95 }
96 }
97 return compiler_type;
98 }
99
100 namespace lldb_private {
101 namespace formatters {
102 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
103 public:
104 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
105
106 ~NSDictionaryISyntheticFrontEnd() override;
107
108 size_t CalculateNumChildren() override;
109
110 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
111
112 bool Update() override;
113
114 bool MightHaveChildren() override;
115
116 size_t GetIndexOfChildWithName(ConstString name) override;
117
118 private:
119 struct DataDescriptor_32 {
120 uint32_t _used : 26;
121 uint32_t _szidx : 6;
122 };
123
124 struct DataDescriptor_64 {
125 uint64_t _used : 58;
126 uint32_t _szidx : 6;
127 };
128
129 struct DictionaryItemDescriptor {
130 lldb::addr_t key_ptr;
131 lldb::addr_t val_ptr;
132 lldb::ValueObjectSP valobj_sp;
133 };
134
135 ExecutionContextRef m_exe_ctx_ref;
136 uint8_t m_ptr_size;
137 lldb::ByteOrder m_order;
138 DataDescriptor_32 *m_data_32;
139 DataDescriptor_64 *m_data_64;
140 lldb::addr_t m_data_ptr;
141 CompilerType m_pair_type;
142 std::vector<DictionaryItemDescriptor> m_children;
143 };
144
145 class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
146 public:
147 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
148
149 size_t CalculateNumChildren() override;
150
151 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
152
153 bool Update() override;
154
155 bool MightHaveChildren() override;
156
157 size_t GetIndexOfChildWithName(ConstString name) override;
158
159 private:
160 struct DictionaryItemDescriptor {
161 lldb::addr_t key_ptr;
162 lldb::addr_t val_ptr;
163 lldb::ValueObjectSP valobj_sp;
164 };
165
166 ExecutionContextRef m_exe_ctx_ref;
167 uint8_t m_ptr_size;
168 lldb::ByteOrder m_order;
169
170 CFBasicHash m_hashtable;
171
172 CompilerType m_pair_type;
173 std::vector<DictionaryItemDescriptor> m_children;
174 };
175
176 class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
177 public:
178 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
179
180 ~NSDictionary1SyntheticFrontEnd() override = default;
181
182 size_t CalculateNumChildren() override;
183
184 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
185
186 bool Update() override;
187
188 bool MightHaveChildren() override;
189
190 size_t GetIndexOfChildWithName(ConstString name) override;
191
192 private:
193 ValueObjectSP m_pair;
194 };
195
196 template <typename D32, typename D64>
197 class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
198 public:
199 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
200
201 ~GenericNSDictionaryMSyntheticFrontEnd() override;
202
203 size_t CalculateNumChildren() override;
204
205 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
206
207 bool Update() override;
208
209 bool MightHaveChildren() override;
210
211 size_t GetIndexOfChildWithName(ConstString name) override;
212
213 private:
214 struct DictionaryItemDescriptor {
215 lldb::addr_t key_ptr;
216 lldb::addr_t val_ptr;
217 lldb::ValueObjectSP valobj_sp;
218 };
219
220 ExecutionContextRef m_exe_ctx_ref;
221 uint8_t m_ptr_size;
222 lldb::ByteOrder m_order;
223 D32 *m_data_32;
224 D64 *m_data_64;
225 CompilerType m_pair_type;
226 std::vector<DictionaryItemDescriptor> m_children;
227 };
228
229 namespace Foundation1100 {
230 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
231 public:
232 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
233
234 ~NSDictionaryMSyntheticFrontEnd() override;
235
236 size_t CalculateNumChildren() override;
237
238 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
239
240 bool Update() override;
241
242 bool MightHaveChildren() override;
243
244 size_t GetIndexOfChildWithName(ConstString name) override;
245
246 private:
247 struct DataDescriptor_32 {
248 uint32_t _used : 26;
249 uint32_t _kvo : 1;
250 uint32_t _size;
251 uint32_t _mutations;
252 uint32_t _objs_addr;
253 uint32_t _keys_addr;
254 };
255
256 struct DataDescriptor_64 {
257 uint64_t _used : 58;
258 uint32_t _kvo : 1;
259 uint64_t _size;
260 uint64_t _mutations;
261 uint64_t _objs_addr;
262 uint64_t _keys_addr;
263 };
264
265 struct DictionaryItemDescriptor {
266 lldb::addr_t key_ptr;
267 lldb::addr_t val_ptr;
268 lldb::ValueObjectSP valobj_sp;
269 };
270
271 ExecutionContextRef m_exe_ctx_ref;
272 uint8_t m_ptr_size;
273 lldb::ByteOrder m_order;
274 DataDescriptor_32 *m_data_32;
275 DataDescriptor_64 *m_data_64;
276 CompilerType m_pair_type;
277 std::vector<DictionaryItemDescriptor> m_children;
278 };
279 }
280
281 namespace Foundation1428 {
282 namespace {
283 struct DataDescriptor_32 {
284 uint32_t _used : 26;
285 uint32_t _kvo : 1;
286 uint32_t _size;
287 uint32_t _buffer;
GetSizelldb_private::formatters::Foundation1428::__anon359a88ac0111::DataDescriptor_32288 uint64_t GetSize() { return _size; }
289 };
290
291 struct DataDescriptor_64 {
292 uint64_t _used : 58;
293 uint32_t _kvo : 1;
294 uint64_t _size;
295 uint64_t _buffer;
GetSizelldb_private::formatters::Foundation1428::__anon359a88ac0111::DataDescriptor_64296 uint64_t GetSize() { return _size; }
297 };
298 }
299
300 using NSDictionaryMSyntheticFrontEnd =
301 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
302 }
303
304 namespace Foundation1437 {
305 namespace {
306 static const uint64_t NSDictionaryCapacities[] = {
307 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
308 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
309 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
310 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
311 111638519, 180634607, 292272623, 472907251
312 };
313
314 static const size_t NSDictionaryNumSizeBuckets =
315 sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
316
317 struct DataDescriptor_32 {
318 uint32_t _buffer;
319 uint32_t _muts;
320 uint32_t _used : 25;
321 uint32_t _kvo : 1;
322 uint32_t _szidx : 6;
323
GetSizelldb_private::formatters::Foundation1437::__anon359a88ac0211::DataDescriptor_32324 uint64_t GetSize() {
325 return (_szidx) >= NSDictionaryNumSizeBuckets ?
326 0 : NSDictionaryCapacities[_szidx];
327 }
328 };
329
330 struct DataDescriptor_64 {
331 uint64_t _buffer;
332 uint32_t _muts;
333 uint32_t _used : 25;
334 uint32_t _kvo : 1;
335 uint32_t _szidx : 6;
336
GetSizelldb_private::formatters::Foundation1437::__anon359a88ac0211::DataDescriptor_64337 uint64_t GetSize() {
338 return (_szidx) >= NSDictionaryNumSizeBuckets ?
339 0 : NSDictionaryCapacities[_szidx];
340 }
341 };
342 }
343
344 using NSDictionaryMSyntheticFrontEnd =
345 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
346
347 template <typename DD>
348 uint64_t
__NSDictionaryMSize_Impl(lldb_private::Process & process,lldb::addr_t valobj_addr,Status & error)349 __NSDictionaryMSize_Impl(lldb_private::Process &process,
350 lldb::addr_t valobj_addr, Status &error) {
351 const lldb::addr_t start_of_descriptor =
352 valobj_addr + process.GetAddressByteSize();
353 DD descriptor = DD();
354 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
355 error);
356 if (error.Fail()) {
357 return 0;
358 }
359 return descriptor._used;
360 }
361
362 uint64_t
__NSDictionaryMSize(lldb_private::Process & process,lldb::addr_t valobj_addr,Status & error)363 __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
364 Status &error) {
365 if (process.GetAddressByteSize() == 4) {
366 return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
367 error);
368 } else {
369 return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
370 error);
371 }
372 }
373
374 }
375 } // namespace formatters
376 } // namespace lldb_private
377
378 template <bool name_entries>
NSDictionarySummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)379 bool lldb_private::formatters::NSDictionarySummaryProvider(
380 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
381 static ConstString g_TypeHint("NSDictionary");
382 ProcessSP process_sp = valobj.GetProcessSP();
383 if (!process_sp)
384 return false;
385
386 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
387
388 if (!runtime)
389 return false;
390
391 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
392 runtime->GetNonKVOClassDescriptor(valobj));
393
394 if (!descriptor || !descriptor->IsValid())
395 return false;
396
397 uint32_t ptr_size = process_sp->GetAddressByteSize();
398 bool is_64bit = (ptr_size == 8);
399
400 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
401
402 if (!valobj_addr)
403 return false;
404
405 uint64_t value = 0;
406
407 ConstString class_name(descriptor->GetClassName());
408
409 static const ConstString g_DictionaryI("__NSDictionaryI");
410 static const ConstString g_DictionaryM("__NSDictionaryM");
411 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
412 static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
413 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
414 static const ConstString g_Dictionary0("__NSDictionary0");
415 static const ConstString g_DictionaryCF("__CFDictionary");
416 static const ConstString g_DictionaryNSCF("__NSCFDictionary");
417 static const ConstString g_DictionaryCFRef("CFDictionaryRef");
418
419 if (class_name.IsEmpty())
420 return false;
421
422 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
423 Status error;
424 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
425 ptr_size, 0, error);
426 if (error.Fail())
427 return false;
428
429 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
430 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) {
431 AppleObjCRuntime *apple_runtime =
432 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
433 Status error;
434 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
435 value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
436 error);
437 } else {
438 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
439 ptr_size, 0, error);
440 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
441 }
442 if (error.Fail())
443 return false;
444 } else if (class_name == g_Dictionary1) {
445 value = 1;
446 } else if (class_name == g_Dictionary0) {
447 value = 0;
448 } else if (class_name == g_DictionaryCF ||
449 class_name == g_DictionaryNSCF ||
450 class_name == g_DictionaryCFRef) {
451 ExecutionContext exe_ctx(process_sp);
452 CFBasicHash cfbh;
453 if (!cfbh.Update(valobj_addr, exe_ctx))
454 return false;
455 value = cfbh.GetCount();
456 } else {
457 auto &map(NSDictionary_Additionals::GetAdditionalSummaries());
458 for (auto &candidate : map) {
459 if (candidate.first && candidate.first->Match(class_name))
460 return candidate.second(valobj, stream, options);
461 }
462 return false;
463 }
464
465 std::string prefix, suffix;
466 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
467 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
468 suffix)) {
469 prefix.clear();
470 suffix.clear();
471 }
472 }
473
474 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair",
475 value == 1 ? "" : "s", suffix.c_str());
476 return true;
477 }
478
479 SyntheticChildrenFrontEnd *
NSDictionarySyntheticFrontEndCreator(CXXSyntheticChildren * synth,lldb::ValueObjectSP valobj_sp)480 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
481 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
482 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
483 if (!process_sp)
484 return nullptr;
485 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
486 ObjCLanguageRuntime::Get(*process_sp));
487 if (!runtime)
488 return nullptr;
489
490 CompilerType valobj_type(valobj_sp->GetCompilerType());
491 Flags flags(valobj_type.GetTypeInfo());
492
493 if (flags.IsClear(eTypeIsPointer)) {
494 Status error;
495 valobj_sp = valobj_sp->AddressOf(error);
496 if (error.Fail() || !valobj_sp)
497 return nullptr;
498 }
499
500 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
501 runtime->GetClassDescriptor(*valobj_sp));
502
503 if (!descriptor || !descriptor->IsValid())
504 return nullptr;
505
506 ConstString class_name(descriptor->GetClassName());
507
508 static const ConstString g_DictionaryI("__NSDictionaryI");
509 static const ConstString g_DictionaryM("__NSDictionaryM");
510 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
511 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
512 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
513 static const ConstString g_Dictionary0("__NSDictionary0");
514 static const ConstString g_DictionaryCF("__CFDictionary");
515 static const ConstString g_DictionaryNSCF("__NSCFDictionary");
516 static const ConstString g_DictionaryCFRef("CFDictionaryRef");
517
518 if (class_name.IsEmpty())
519 return nullptr;
520
521 if (class_name == g_DictionaryI) {
522 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
523 } else if (class_name == g_DictionaryM) {
524 if (runtime->GetFoundationVersion() >= 1437) {
525 return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
526 } else if (runtime->GetFoundationVersion() >= 1428) {
527 return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));
528 } else {
529 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
530 }
531 } else if (class_name == g_DictionaryMLegacy) {
532 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
533 } else if (class_name == g_Dictionary1) {
534 return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
535 } else if (class_name == g_DictionaryCF ||
536 class_name == g_DictionaryNSCF ||
537 class_name == g_DictionaryCFRef) {
538 return (new NSCFDictionarySyntheticFrontEnd(valobj_sp));
539 } else {
540 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());
541 for (auto &candidate : map) {
542 if (candidate.first && candidate.first->Match((class_name)))
543 return candidate.second(synth, valobj_sp);
544 }
545 }
546
547 return nullptr;
548 }
549
550 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)551 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
552 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
553 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
554 m_pair_type() {}
555
556 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
~NSDictionaryISyntheticFrontEnd()557 ~NSDictionaryISyntheticFrontEnd() {
558 delete m_data_32;
559 m_data_32 = nullptr;
560 delete m_data_64;
561 m_data_64 = nullptr;
562 }
563
564 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)565 GetIndexOfChildWithName(ConstString name) {
566 const char *item_name = name.GetCString();
567 uint32_t idx = ExtractIndexFromString(item_name);
568 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
569 return UINT32_MAX;
570 return idx;
571 }
572
573 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
CalculateNumChildren()574 CalculateNumChildren() {
575 if (!m_data_32 && !m_data_64)
576 return 0;
577 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
578 }
579
Update()580 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
581 m_children.clear();
582 delete m_data_32;
583 m_data_32 = nullptr;
584 delete m_data_64;
585 m_data_64 = nullptr;
586 m_ptr_size = 0;
587 ValueObjectSP valobj_sp = m_backend.GetSP();
588 if (!valobj_sp)
589 return false;
590 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
591 Status error;
592 error.Clear();
593 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
594 if (!process_sp)
595 return false;
596 m_ptr_size = process_sp->GetAddressByteSize();
597 m_order = process_sp->GetByteOrder();
598 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
599 if (m_ptr_size == 4) {
600 m_data_32 = new DataDescriptor_32();
601 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
602 error);
603 } else {
604 m_data_64 = new DataDescriptor_64();
605 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
606 error);
607 }
608 if (error.Fail())
609 return false;
610 m_data_ptr = data_location + m_ptr_size;
611 return false;
612 }
613
614 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
MightHaveChildren()615 MightHaveChildren() {
616 return true;
617 }
618
619 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)620 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
621 size_t idx) {
622 uint32_t num_children = CalculateNumChildren();
623
624 if (idx >= num_children)
625 return lldb::ValueObjectSP();
626
627 if (m_children.empty()) {
628 // do the scan phase
629 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
630
631 uint32_t tries = 0;
632 uint32_t test_idx = 0;
633
634 while (tries < num_children) {
635 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
636 val_at_idx = key_at_idx + m_ptr_size;
637 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
638 if (!process_sp)
639 return lldb::ValueObjectSP();
640 Status error;
641 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
642 if (error.Fail())
643 return lldb::ValueObjectSP();
644 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
645 if (error.Fail())
646 return lldb::ValueObjectSP();
647
648 test_idx++;
649
650 if (!key_at_idx || !val_at_idx)
651 continue;
652 tries++;
653
654 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
655 lldb::ValueObjectSP()};
656
657 m_children.push_back(descriptor);
658 }
659 }
660
661 if (idx >= m_children.size()) // should never happen
662 return lldb::ValueObjectSP();
663
664 DictionaryItemDescriptor &dict_item = m_children[idx];
665 if (!dict_item.valobj_sp) {
666 if (!m_pair_type.IsValid()) {
667 TargetSP target_sp(m_backend.GetTargetSP());
668 if (!target_sp)
669 return ValueObjectSP();
670 m_pair_type = GetLLDBNSPairType(target_sp);
671 }
672 if (!m_pair_type.IsValid())
673 return ValueObjectSP();
674
675 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
676
677 if (m_ptr_size == 8) {
678 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
679 *data_ptr = dict_item.key_ptr;
680 *(data_ptr + 1) = dict_item.val_ptr;
681 } else {
682 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
683 *data_ptr = dict_item.key_ptr;
684 *(data_ptr + 1) = dict_item.val_ptr;
685 }
686
687 StreamString idx_name;
688 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
689 DataExtractor data(buffer_sp, m_order, m_ptr_size);
690 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
691 m_exe_ctx_ref, m_pair_type);
692 }
693 return dict_item.valobj_sp;
694 }
695
696 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)697 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
698 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
699 m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {}
700
701 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)702 GetIndexOfChildWithName(ConstString name) {
703 const char *item_name = name.GetCString();
704 const uint32_t idx = ExtractIndexFromString(item_name);
705 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
706 return UINT32_MAX;
707 return idx;
708 }
709
710 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
CalculateNumChildren()711 CalculateNumChildren() {
712 if (!m_hashtable.IsValid())
713 return 0;
714 return m_hashtable.GetCount();
715 }
716
Update()717 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {
718 m_children.clear();
719 ValueObjectSP valobj_sp = m_backend.GetSP();
720 m_ptr_size = 0;
721 if (!valobj_sp)
722 return false;
723 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
724
725 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
726 if (!process_sp)
727 return false;
728 m_ptr_size = process_sp->GetAddressByteSize();
729 m_order = process_sp->GetByteOrder();
730 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref);
731 }
732
733 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
MightHaveChildren()734 MightHaveChildren() {
735 return true;
736 }
737
738 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)739 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
740 size_t idx) {
741 lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer();
742 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
743
744 const uint32_t num_children = CalculateNumChildren();
745
746 if (idx >= num_children)
747 return lldb::ValueObjectSP();
748
749 if (m_children.empty()) {
750 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
751 if (!process_sp)
752 return lldb::ValueObjectSP();
753
754 Status error;
755 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
756
757 uint32_t tries = 0;
758 uint32_t test_idx = 0;
759
760 // Iterate over inferior memory, reading key/value pointers by shifting each
761 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
762 // fails, otherwise, continue until the number of tries matches the number
763 // of childen.
764 while (tries < num_children) {
765 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
766 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
767
768 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
769 if (error.Fail())
770 return lldb::ValueObjectSP();
771 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
772 if (error.Fail())
773 return lldb::ValueObjectSP();
774
775 test_idx++;
776
777 if (!key_at_idx || !val_at_idx)
778 continue;
779 tries++;
780
781 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
782 lldb::ValueObjectSP()};
783
784 m_children.push_back(descriptor);
785 }
786 }
787
788 if (idx >= m_children.size()) // should never happen
789 return lldb::ValueObjectSP();
790
791 DictionaryItemDescriptor &dict_item = m_children[idx];
792 if (!dict_item.valobj_sp) {
793 if (!m_pair_type.IsValid()) {
794 TargetSP target_sp(m_backend.GetTargetSP());
795 if (!target_sp)
796 return ValueObjectSP();
797 m_pair_type = GetLLDBNSPairType(target_sp);
798 }
799 if (!m_pair_type.IsValid())
800 return ValueObjectSP();
801
802 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
803
804 switch (m_ptr_size) {
805 case 0: // architecture has no clue - fail
806 return lldb::ValueObjectSP();
807 case 4: {
808 uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes());
809 *data_ptr = dict_item.key_ptr;
810 *(data_ptr + 1) = dict_item.val_ptr;
811 } break;
812 case 8: {
813 uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes());
814 *data_ptr = dict_item.key_ptr;
815 *(data_ptr + 1) = dict_item.val_ptr;
816 } break;
817 default:
818 lldbassert(false && "pointer size is not 4 nor 8");
819 }
820
821 StreamString idx_name;
822 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
823 DataExtractor data(buffer_sp, m_order, m_ptr_size);
824 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
825 m_exe_ctx_ref, m_pair_type);
826 }
827 return dict_item.valobj_sp;
828 }
829
830 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)831 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
832 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
833
834 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)835 GetIndexOfChildWithName(ConstString name) {
836 static const ConstString g_zero("[0]");
837 return name == g_zero ? 0 : UINT32_MAX;
838 }
839
840 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
CalculateNumChildren()841 CalculateNumChildren() {
842 return 1;
843 }
844
Update()845 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
846 m_pair.reset();
847 return false;
848 }
849
850 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
MightHaveChildren()851 MightHaveChildren() {
852 return true;
853 }
854
855 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)856 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
857 size_t idx) {
858 if (idx != 0)
859 return lldb::ValueObjectSP();
860
861 if (m_pair.get())
862 return m_pair;
863
864 auto process_sp(m_backend.GetProcessSP());
865 if (!process_sp)
866 return nullptr;
867
868 auto ptr_size = process_sp->GetAddressByteSize();
869
870 lldb::addr_t key_ptr =
871 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
872 lldb::addr_t value_ptr = key_ptr + ptr_size;
873
874 Status error;
875
876 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
877 if (error.Fail())
878 return nullptr;
879 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
880 if (error.Fail())
881 return nullptr;
882
883 auto pair_type =
884 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
885
886 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
887
888 if (ptr_size == 8) {
889 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
890 *data_ptr = key_at_idx;
891 *(data_ptr + 1) = value_at_idx;
892 } else {
893 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
894 *data_ptr = key_at_idx;
895 *(data_ptr + 1) = value_at_idx;
896 }
897
898 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
899 m_pair = CreateValueObjectFromData(
900 "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
901
902 return m_pair;
903 }
904
905 template <typename D32, typename D64>
906 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)907 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
908 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
909 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
910 m_pair_type() {}
911
912 template <typename D32, typename D64>
913 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
~GenericNSDictionaryMSyntheticFrontEnd()914 ~GenericNSDictionaryMSyntheticFrontEnd<D32,D64>() {
915 delete m_data_32;
916 m_data_32 = nullptr;
917 delete m_data_64;
918 m_data_64 = nullptr;
919 }
920
921 template <typename D32, typename D64>
922 size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
GetIndexOfChildWithName(ConstString name)923 D32, D64>::GetIndexOfChildWithName(ConstString name) {
924 const char *item_name = name.GetCString();
925 uint32_t idx = ExtractIndexFromString(item_name);
926 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
927 return UINT32_MAX;
928 return idx;
929 }
930
931 template <typename D32, typename D64>
932 size_t
CalculateNumChildren()933 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() {
934 if (!m_data_32 && !m_data_64)
935 return 0;
936 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
937 }
938
939 template <typename D32, typename D64>
940 bool
941 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
Update()942 Update() {
943 m_children.clear();
944 ValueObjectSP valobj_sp = m_backend.GetSP();
945 m_ptr_size = 0;
946 delete m_data_32;
947 m_data_32 = nullptr;
948 delete m_data_64;
949 m_data_64 = nullptr;
950 if (!valobj_sp)
951 return false;
952 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
953 Status error;
954 error.Clear();
955 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
956 if (!process_sp)
957 return false;
958 m_ptr_size = process_sp->GetAddressByteSize();
959 m_order = process_sp->GetByteOrder();
960 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
961 if (m_ptr_size == 4) {
962 m_data_32 = new D32();
963 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
964 error);
965 } else {
966 m_data_64 = new D64();
967 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
968 error);
969 }
970 if (error.Fail())
971 return false;
972 return true;
973 }
974
975 template <typename D32, typename D64>
976 bool
977 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
MightHaveChildren()978 MightHaveChildren() {
979 return true;
980 }
981
982 template <typename D32, typename D64>
983 lldb::ValueObjectSP
984 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
GetChildAtIndex(size_t idx)985 D32, D64>::GetChildAtIndex(size_t idx) {
986 lldb::addr_t m_keys_ptr;
987 lldb::addr_t m_values_ptr;
988 if (m_data_32) {
989 uint32_t size = m_data_32->GetSize();
990 m_keys_ptr = m_data_32->_buffer;
991 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
992 } else {
993 uint32_t size = m_data_64->GetSize();
994 m_keys_ptr = m_data_64->_buffer;
995 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
996 }
997
998 uint32_t num_children = CalculateNumChildren();
999
1000 if (idx >= num_children)
1001 return lldb::ValueObjectSP();
1002
1003 if (m_children.empty()) {
1004 // do the scan phase
1005 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1006
1007 uint32_t tries = 0;
1008 uint32_t test_idx = 0;
1009
1010 while (tries < num_children) {
1011 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1012 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1013 ;
1014 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1015 if (!process_sp)
1016 return lldb::ValueObjectSP();
1017 Status error;
1018 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1019 if (error.Fail())
1020 return lldb::ValueObjectSP();
1021 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1022 if (error.Fail())
1023 return lldb::ValueObjectSP();
1024
1025 test_idx++;
1026
1027 if (!key_at_idx || !val_at_idx)
1028 continue;
1029 tries++;
1030
1031 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1032 lldb::ValueObjectSP()};
1033
1034 m_children.push_back(descriptor);
1035 }
1036 }
1037
1038 if (idx >= m_children.size()) // should never happen
1039 return lldb::ValueObjectSP();
1040
1041 DictionaryItemDescriptor &dict_item = m_children[idx];
1042 if (!dict_item.valobj_sp) {
1043 if (!m_pair_type.IsValid()) {
1044 TargetSP target_sp(m_backend.GetTargetSP());
1045 if (!target_sp)
1046 return ValueObjectSP();
1047 m_pair_type = GetLLDBNSPairType(target_sp);
1048 }
1049 if (!m_pair_type.IsValid())
1050 return ValueObjectSP();
1051
1052 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1053
1054 if (m_ptr_size == 8) {
1055 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1056 *data_ptr = dict_item.key_ptr;
1057 *(data_ptr + 1) = dict_item.val_ptr;
1058 } else {
1059 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1060 *data_ptr = dict_item.key_ptr;
1061 *(data_ptr + 1) = dict_item.val_ptr;
1062 }
1063
1064 StreamString idx_name;
1065 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1066 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1067 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1068 m_exe_ctx_ref, m_pair_type);
1069 }
1070 return dict_item.valobj_sp;
1071 }
1072
1073 lldb_private::formatters::Foundation1100::
1074 NSDictionaryMSyntheticFrontEnd::
NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)1075 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
1076 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
1077 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
1078 m_pair_type() {}
1079
1080 lldb_private::formatters::Foundation1100::
~NSDictionaryMSyntheticFrontEnd()1081 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {
1082 delete m_data_32;
1083 m_data_32 = nullptr;
1084 delete m_data_64;
1085 m_data_64 = nullptr;
1086 }
1087
1088 size_t
1089 lldb_private::formatters::Foundation1100::
GetIndexOfChildWithName(ConstString name)1090 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
1091 const char *item_name = name.GetCString();
1092 uint32_t idx = ExtractIndexFromString(item_name);
1093 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1094 return UINT32_MAX;
1095 return idx;
1096 }
1097
1098 size_t
1099 lldb_private::formatters::Foundation1100::
CalculateNumChildren()1100 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
1101 if (!m_data_32 && !m_data_64)
1102 return 0;
1103 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1104 }
1105
1106 bool
1107 lldb_private::formatters::Foundation1100::
Update()1108 NSDictionaryMSyntheticFrontEnd::Update() {
1109 m_children.clear();
1110 ValueObjectSP valobj_sp = m_backend.GetSP();
1111 m_ptr_size = 0;
1112 delete m_data_32;
1113 m_data_32 = nullptr;
1114 delete m_data_64;
1115 m_data_64 = nullptr;
1116 if (!valobj_sp)
1117 return false;
1118 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1119 Status error;
1120 error.Clear();
1121 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1122 if (!process_sp)
1123 return false;
1124 m_ptr_size = process_sp->GetAddressByteSize();
1125 m_order = process_sp->GetByteOrder();
1126 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1127 if (m_ptr_size == 4) {
1128 m_data_32 = new DataDescriptor_32();
1129 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
1130 error);
1131 } else {
1132 m_data_64 = new DataDescriptor_64();
1133 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
1134 error);
1135 }
1136 if (error.Fail())
1137 return false;
1138 return false;
1139 }
1140
1141 bool
1142 lldb_private::formatters::Foundation1100::
MightHaveChildren()1143 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
1144 return true;
1145 }
1146
1147 lldb::ValueObjectSP
1148 lldb_private::formatters::Foundation1100::
GetChildAtIndex(size_t idx)1149 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
1150 lldb::addr_t m_keys_ptr =
1151 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
1152 lldb::addr_t m_values_ptr =
1153 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
1154
1155 uint32_t num_children = CalculateNumChildren();
1156
1157 if (idx >= num_children)
1158 return lldb::ValueObjectSP();
1159
1160 if (m_children.empty()) {
1161 // do the scan phase
1162 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1163
1164 uint32_t tries = 0;
1165 uint32_t test_idx = 0;
1166
1167 while (tries < num_children) {
1168 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1169 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1170 ;
1171 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1172 if (!process_sp)
1173 return lldb::ValueObjectSP();
1174 Status error;
1175 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1176 if (error.Fail())
1177 return lldb::ValueObjectSP();
1178 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1179 if (error.Fail())
1180 return lldb::ValueObjectSP();
1181
1182 test_idx++;
1183
1184 if (!key_at_idx || !val_at_idx)
1185 continue;
1186 tries++;
1187
1188 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1189 lldb::ValueObjectSP()};
1190
1191 m_children.push_back(descriptor);
1192 }
1193 }
1194
1195 if (idx >= m_children.size()) // should never happen
1196 return lldb::ValueObjectSP();
1197
1198 DictionaryItemDescriptor &dict_item = m_children[idx];
1199 if (!dict_item.valobj_sp) {
1200 if (!m_pair_type.IsValid()) {
1201 TargetSP target_sp(m_backend.GetTargetSP());
1202 if (!target_sp)
1203 return ValueObjectSP();
1204 m_pair_type = GetLLDBNSPairType(target_sp);
1205 }
1206 if (!m_pair_type.IsValid())
1207 return ValueObjectSP();
1208
1209 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1210
1211 if (m_ptr_size == 8) {
1212 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1213 *data_ptr = dict_item.key_ptr;
1214 *(data_ptr + 1) = dict_item.val_ptr;
1215 } else {
1216 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1217 *data_ptr = dict_item.key_ptr;
1218 *(data_ptr + 1) = dict_item.val_ptr;
1219 }
1220
1221 StreamString idx_name;
1222 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1223 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1224 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1225 m_exe_ctx_ref, m_pair_type);
1226 }
1227 return dict_item.valobj_sp;
1228 }
1229
1230 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(
1231 ValueObject &, Stream &, const TypeSummaryOptions &);
1232
1233 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(
1234 ValueObject &, Stream &, const TypeSummaryOptions &);
1235