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::__anon6e5aa7db0111::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::__anon6e5aa7db0111::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::__anon6e5aa7db0211::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::__anon6e5aa7db0211::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_DictionaryMFrozen("__NSFrozenDictionaryM");
414 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
415 static const ConstString g_Dictionary0("__NSDictionary0");
416 static const ConstString g_DictionaryCF("__CFDictionary");
417 static const ConstString g_DictionaryNSCF("__NSCFDictionary");
418 static const ConstString g_DictionaryCFRef("CFDictionaryRef");
419
420 if (class_name.IsEmpty())
421 return false;
422
423 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
424 Status error;
425 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
426 ptr_size, 0, error);
427 if (error.Fail())
428 return false;
429
430 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
431 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy
432 || class_name == g_DictionaryMFrozen) {
433 AppleObjCRuntime *apple_runtime =
434 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
435 Status error;
436 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
437 value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
438 error);
439 } else {
440 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
441 ptr_size, 0, error);
442 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
443 }
444 if (error.Fail())
445 return false;
446 } else if (class_name == g_Dictionary1) {
447 value = 1;
448 } else if (class_name == g_Dictionary0) {
449 value = 0;
450 } else if (class_name == g_DictionaryCF ||
451 class_name == g_DictionaryNSCF ||
452 class_name == g_DictionaryCFRef) {
453 ExecutionContext exe_ctx(process_sp);
454 CFBasicHash cfbh;
455 if (!cfbh.Update(valobj_addr, exe_ctx))
456 return false;
457 value = cfbh.GetCount();
458 } else {
459 auto &map(NSDictionary_Additionals::GetAdditionalSummaries());
460 for (auto &candidate : map) {
461 if (candidate.first && candidate.first->Match(class_name))
462 return candidate.second(valobj, stream, options);
463 }
464 return false;
465 }
466
467 std::string prefix, suffix;
468 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
469 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
470 suffix)) {
471 prefix.clear();
472 suffix.clear();
473 }
474 }
475
476 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair",
477 value == 1 ? "" : "s", suffix.c_str());
478 return true;
479 }
480
481 SyntheticChildrenFrontEnd *
NSDictionarySyntheticFrontEndCreator(CXXSyntheticChildren * synth,lldb::ValueObjectSP valobj_sp)482 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
483 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
484 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
485 if (!process_sp)
486 return nullptr;
487 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
488 ObjCLanguageRuntime::Get(*process_sp));
489 if (!runtime)
490 return nullptr;
491
492 CompilerType valobj_type(valobj_sp->GetCompilerType());
493 Flags flags(valobj_type.GetTypeInfo());
494
495 if (flags.IsClear(eTypeIsPointer)) {
496 Status error;
497 valobj_sp = valobj_sp->AddressOf(error);
498 if (error.Fail() || !valobj_sp)
499 return nullptr;
500 }
501
502 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
503 runtime->GetClassDescriptor(*valobj_sp));
504
505 if (!descriptor || !descriptor->IsValid())
506 return nullptr;
507
508 ConstString class_name(descriptor->GetClassName());
509
510 static const ConstString g_DictionaryI("__NSDictionaryI");
511 static const ConstString g_DictionaryM("__NSDictionaryM");
512 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
513 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
514 static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");
515 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
516 static const ConstString g_Dictionary0("__NSDictionary0");
517 static const ConstString g_DictionaryCF("__CFDictionary");
518 static const ConstString g_DictionaryNSCF("__NSCFDictionary");
519 static const ConstString g_DictionaryCFRef("CFDictionaryRef");
520
521 if (class_name.IsEmpty())
522 return nullptr;
523
524 if (class_name == g_DictionaryI) {
525 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
526 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) {
527 if (runtime->GetFoundationVersion() >= 1437) {
528 return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
529 } else if (runtime->GetFoundationVersion() >= 1428) {
530 return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));
531 } else {
532 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
533 }
534 } else if (class_name == g_DictionaryMLegacy) {
535 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
536 } else if (class_name == g_Dictionary1) {
537 return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
538 } else if (class_name == g_DictionaryCF ||
539 class_name == g_DictionaryNSCF ||
540 class_name == g_DictionaryCFRef) {
541 return (new NSCFDictionarySyntheticFrontEnd(valobj_sp));
542 } else {
543 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());
544 for (auto &candidate : map) {
545 if (candidate.first && candidate.first->Match((class_name)))
546 return candidate.second(synth, valobj_sp);
547 }
548 }
549
550 return nullptr;
551 }
552
553 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)554 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
555 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
556 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
557 m_pair_type() {}
558
559 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
~NSDictionaryISyntheticFrontEnd()560 ~NSDictionaryISyntheticFrontEnd() {
561 delete m_data_32;
562 m_data_32 = nullptr;
563 delete m_data_64;
564 m_data_64 = nullptr;
565 }
566
567 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)568 GetIndexOfChildWithName(ConstString name) {
569 const char *item_name = name.GetCString();
570 uint32_t idx = ExtractIndexFromString(item_name);
571 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
572 return UINT32_MAX;
573 return idx;
574 }
575
576 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
CalculateNumChildren()577 CalculateNumChildren() {
578 if (!m_data_32 && !m_data_64)
579 return 0;
580 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
581 }
582
Update()583 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
584 m_children.clear();
585 delete m_data_32;
586 m_data_32 = nullptr;
587 delete m_data_64;
588 m_data_64 = nullptr;
589 m_ptr_size = 0;
590 ValueObjectSP valobj_sp = m_backend.GetSP();
591 if (!valobj_sp)
592 return false;
593 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
594 Status error;
595 error.Clear();
596 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
597 if (!process_sp)
598 return false;
599 m_ptr_size = process_sp->GetAddressByteSize();
600 m_order = process_sp->GetByteOrder();
601 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
602 if (m_ptr_size == 4) {
603 m_data_32 = new DataDescriptor_32();
604 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
605 error);
606 } else {
607 m_data_64 = new DataDescriptor_64();
608 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
609 error);
610 }
611 if (error.Fail())
612 return false;
613 m_data_ptr = data_location + m_ptr_size;
614 return false;
615 }
616
617 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
MightHaveChildren()618 MightHaveChildren() {
619 return true;
620 }
621
622 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)623 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
624 size_t idx) {
625 uint32_t num_children = CalculateNumChildren();
626
627 if (idx >= num_children)
628 return lldb::ValueObjectSP();
629
630 if (m_children.empty()) {
631 // do the scan phase
632 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
633
634 uint32_t tries = 0;
635 uint32_t test_idx = 0;
636
637 while (tries < num_children) {
638 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
639 val_at_idx = key_at_idx + m_ptr_size;
640 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
641 if (!process_sp)
642 return lldb::ValueObjectSP();
643 Status error;
644 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
645 if (error.Fail())
646 return lldb::ValueObjectSP();
647 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
648 if (error.Fail())
649 return lldb::ValueObjectSP();
650
651 test_idx++;
652
653 if (!key_at_idx || !val_at_idx)
654 continue;
655 tries++;
656
657 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
658 lldb::ValueObjectSP()};
659
660 m_children.push_back(descriptor);
661 }
662 }
663
664 if (idx >= m_children.size()) // should never happen
665 return lldb::ValueObjectSP();
666
667 DictionaryItemDescriptor &dict_item = m_children[idx];
668 if (!dict_item.valobj_sp) {
669 if (!m_pair_type.IsValid()) {
670 TargetSP target_sp(m_backend.GetTargetSP());
671 if (!target_sp)
672 return ValueObjectSP();
673 m_pair_type = GetLLDBNSPairType(target_sp);
674 }
675 if (!m_pair_type.IsValid())
676 return ValueObjectSP();
677
678 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
679
680 if (m_ptr_size == 8) {
681 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
682 *data_ptr = dict_item.key_ptr;
683 *(data_ptr + 1) = dict_item.val_ptr;
684 } else {
685 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
686 *data_ptr = dict_item.key_ptr;
687 *(data_ptr + 1) = dict_item.val_ptr;
688 }
689
690 StreamString idx_name;
691 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
692 DataExtractor data(buffer_sp, m_order, m_ptr_size);
693 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
694 m_exe_ctx_ref, m_pair_type);
695 }
696 return dict_item.valobj_sp;
697 }
698
699 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)700 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
701 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
702 m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {}
703
704 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)705 GetIndexOfChildWithName(ConstString name) {
706 const char *item_name = name.GetCString();
707 const uint32_t idx = ExtractIndexFromString(item_name);
708 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
709 return UINT32_MAX;
710 return idx;
711 }
712
713 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
CalculateNumChildren()714 CalculateNumChildren() {
715 if (!m_hashtable.IsValid())
716 return 0;
717 return m_hashtable.GetCount();
718 }
719
Update()720 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {
721 m_children.clear();
722 ValueObjectSP valobj_sp = m_backend.GetSP();
723 m_ptr_size = 0;
724 if (!valobj_sp)
725 return false;
726 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
727
728 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
729 if (!process_sp)
730 return false;
731 m_ptr_size = process_sp->GetAddressByteSize();
732 m_order = process_sp->GetByteOrder();
733 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref);
734 }
735
736 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
MightHaveChildren()737 MightHaveChildren() {
738 return true;
739 }
740
741 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)742 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
743 size_t idx) {
744 lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer();
745 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
746
747 const uint32_t num_children = CalculateNumChildren();
748
749 if (idx >= num_children)
750 return lldb::ValueObjectSP();
751
752 if (m_children.empty()) {
753 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
754 if (!process_sp)
755 return lldb::ValueObjectSP();
756
757 Status error;
758 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
759
760 uint32_t tries = 0;
761 uint32_t test_idx = 0;
762
763 // Iterate over inferior memory, reading key/value pointers by shifting each
764 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
765 // fails, otherwise, continue until the number of tries matches the number
766 // of childen.
767 while (tries < num_children) {
768 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
769 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
770
771 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
772 if (error.Fail())
773 return lldb::ValueObjectSP();
774 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
775 if (error.Fail())
776 return lldb::ValueObjectSP();
777
778 test_idx++;
779
780 if (!key_at_idx || !val_at_idx)
781 continue;
782 tries++;
783
784 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
785 lldb::ValueObjectSP()};
786
787 m_children.push_back(descriptor);
788 }
789 }
790
791 if (idx >= m_children.size()) // should never happen
792 return lldb::ValueObjectSP();
793
794 DictionaryItemDescriptor &dict_item = m_children[idx];
795 if (!dict_item.valobj_sp) {
796 if (!m_pair_type.IsValid()) {
797 TargetSP target_sp(m_backend.GetTargetSP());
798 if (!target_sp)
799 return ValueObjectSP();
800 m_pair_type = GetLLDBNSPairType(target_sp);
801 }
802 if (!m_pair_type.IsValid())
803 return ValueObjectSP();
804
805 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
806
807 switch (m_ptr_size) {
808 case 0: // architecture has no clue - fail
809 return lldb::ValueObjectSP();
810 case 4: {
811 uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes());
812 *data_ptr = dict_item.key_ptr;
813 *(data_ptr + 1) = dict_item.val_ptr;
814 } break;
815 case 8: {
816 uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes());
817 *data_ptr = dict_item.key_ptr;
818 *(data_ptr + 1) = dict_item.val_ptr;
819 } break;
820 default:
821 lldbassert(false && "pointer size is not 4 nor 8");
822 }
823
824 StreamString idx_name;
825 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
826 DataExtractor data(buffer_sp, m_order, m_ptr_size);
827 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
828 m_exe_ctx_ref, m_pair_type);
829 }
830 return dict_item.valobj_sp;
831 }
832
833 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)834 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
835 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
836
837 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)838 GetIndexOfChildWithName(ConstString name) {
839 static const ConstString g_zero("[0]");
840 return name == g_zero ? 0 : UINT32_MAX;
841 }
842
843 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
CalculateNumChildren()844 CalculateNumChildren() {
845 return 1;
846 }
847
Update()848 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
849 m_pair.reset();
850 return false;
851 }
852
853 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
MightHaveChildren()854 MightHaveChildren() {
855 return true;
856 }
857
858 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)859 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
860 size_t idx) {
861 if (idx != 0)
862 return lldb::ValueObjectSP();
863
864 if (m_pair.get())
865 return m_pair;
866
867 auto process_sp(m_backend.GetProcessSP());
868 if (!process_sp)
869 return nullptr;
870
871 auto ptr_size = process_sp->GetAddressByteSize();
872
873 lldb::addr_t key_ptr =
874 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
875 lldb::addr_t value_ptr = key_ptr + ptr_size;
876
877 Status error;
878
879 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
880 if (error.Fail())
881 return nullptr;
882 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
883 if (error.Fail())
884 return nullptr;
885
886 auto pair_type =
887 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
888
889 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
890
891 if (ptr_size == 8) {
892 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
893 *data_ptr = key_at_idx;
894 *(data_ptr + 1) = value_at_idx;
895 } else {
896 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
897 *data_ptr = key_at_idx;
898 *(data_ptr + 1) = value_at_idx;
899 }
900
901 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
902 m_pair = CreateValueObjectFromData(
903 "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
904
905 return m_pair;
906 }
907
908 template <typename D32, typename D64>
909 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)910 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
911 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
912 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
913 m_pair_type() {}
914
915 template <typename D32, typename D64>
916 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
~GenericNSDictionaryMSyntheticFrontEnd()917 ~GenericNSDictionaryMSyntheticFrontEnd<D32,D64>() {
918 delete m_data_32;
919 m_data_32 = nullptr;
920 delete m_data_64;
921 m_data_64 = nullptr;
922 }
923
924 template <typename D32, typename D64>
925 size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
GetIndexOfChildWithName(ConstString name)926 D32, D64>::GetIndexOfChildWithName(ConstString name) {
927 const char *item_name = name.GetCString();
928 uint32_t idx = ExtractIndexFromString(item_name);
929 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
930 return UINT32_MAX;
931 return idx;
932 }
933
934 template <typename D32, typename D64>
935 size_t
CalculateNumChildren()936 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() {
937 if (!m_data_32 && !m_data_64)
938 return 0;
939 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
940 }
941
942 template <typename D32, typename D64>
943 bool
944 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
Update()945 Update() {
946 m_children.clear();
947 ValueObjectSP valobj_sp = m_backend.GetSP();
948 m_ptr_size = 0;
949 delete m_data_32;
950 m_data_32 = nullptr;
951 delete m_data_64;
952 m_data_64 = nullptr;
953 if (!valobj_sp)
954 return false;
955 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
956 Status error;
957 error.Clear();
958 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
959 if (!process_sp)
960 return false;
961 m_ptr_size = process_sp->GetAddressByteSize();
962 m_order = process_sp->GetByteOrder();
963 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
964 if (m_ptr_size == 4) {
965 m_data_32 = new D32();
966 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
967 error);
968 } else {
969 m_data_64 = new D64();
970 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
971 error);
972 }
973 if (error.Fail())
974 return false;
975 return true;
976 }
977
978 template <typename D32, typename D64>
979 bool
980 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
MightHaveChildren()981 MightHaveChildren() {
982 return true;
983 }
984
985 template <typename D32, typename D64>
986 lldb::ValueObjectSP
987 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
GetChildAtIndex(size_t idx)988 D32, D64>::GetChildAtIndex(size_t idx) {
989 lldb::addr_t m_keys_ptr;
990 lldb::addr_t m_values_ptr;
991 if (m_data_32) {
992 uint32_t size = m_data_32->GetSize();
993 m_keys_ptr = m_data_32->_buffer;
994 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
995 } else {
996 uint32_t size = m_data_64->GetSize();
997 m_keys_ptr = m_data_64->_buffer;
998 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
999 }
1000
1001 uint32_t num_children = CalculateNumChildren();
1002
1003 if (idx >= num_children)
1004 return lldb::ValueObjectSP();
1005
1006 if (m_children.empty()) {
1007 // do the scan phase
1008 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1009
1010 uint32_t tries = 0;
1011 uint32_t test_idx = 0;
1012
1013 while (tries < num_children) {
1014 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1015 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1016 ;
1017 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1018 if (!process_sp)
1019 return lldb::ValueObjectSP();
1020 Status error;
1021 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1022 if (error.Fail())
1023 return lldb::ValueObjectSP();
1024 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1025 if (error.Fail())
1026 return lldb::ValueObjectSP();
1027
1028 test_idx++;
1029
1030 if (!key_at_idx || !val_at_idx)
1031 continue;
1032 tries++;
1033
1034 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1035 lldb::ValueObjectSP()};
1036
1037 m_children.push_back(descriptor);
1038 }
1039 }
1040
1041 if (idx >= m_children.size()) // should never happen
1042 return lldb::ValueObjectSP();
1043
1044 DictionaryItemDescriptor &dict_item = m_children[idx];
1045 if (!dict_item.valobj_sp) {
1046 if (!m_pair_type.IsValid()) {
1047 TargetSP target_sp(m_backend.GetTargetSP());
1048 if (!target_sp)
1049 return ValueObjectSP();
1050 m_pair_type = GetLLDBNSPairType(target_sp);
1051 }
1052 if (!m_pair_type.IsValid())
1053 return ValueObjectSP();
1054
1055 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1056
1057 if (m_ptr_size == 8) {
1058 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1059 *data_ptr = dict_item.key_ptr;
1060 *(data_ptr + 1) = dict_item.val_ptr;
1061 } else {
1062 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1063 *data_ptr = dict_item.key_ptr;
1064 *(data_ptr + 1) = dict_item.val_ptr;
1065 }
1066
1067 StreamString idx_name;
1068 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1069 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1070 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1071 m_exe_ctx_ref, m_pair_type);
1072 }
1073 return dict_item.valobj_sp;
1074 }
1075
1076 lldb_private::formatters::Foundation1100::
1077 NSDictionaryMSyntheticFrontEnd::
NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)1078 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
1079 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
1080 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
1081 m_pair_type() {}
1082
1083 lldb_private::formatters::Foundation1100::
~NSDictionaryMSyntheticFrontEnd()1084 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {
1085 delete m_data_32;
1086 m_data_32 = nullptr;
1087 delete m_data_64;
1088 m_data_64 = nullptr;
1089 }
1090
1091 size_t
1092 lldb_private::formatters::Foundation1100::
GetIndexOfChildWithName(ConstString name)1093 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
1094 const char *item_name = name.GetCString();
1095 uint32_t idx = ExtractIndexFromString(item_name);
1096 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1097 return UINT32_MAX;
1098 return idx;
1099 }
1100
1101 size_t
1102 lldb_private::formatters::Foundation1100::
CalculateNumChildren()1103 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
1104 if (!m_data_32 && !m_data_64)
1105 return 0;
1106 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1107 }
1108
1109 bool
1110 lldb_private::formatters::Foundation1100::
Update()1111 NSDictionaryMSyntheticFrontEnd::Update() {
1112 m_children.clear();
1113 ValueObjectSP valobj_sp = m_backend.GetSP();
1114 m_ptr_size = 0;
1115 delete m_data_32;
1116 m_data_32 = nullptr;
1117 delete m_data_64;
1118 m_data_64 = nullptr;
1119 if (!valobj_sp)
1120 return false;
1121 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1122 Status error;
1123 error.Clear();
1124 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1125 if (!process_sp)
1126 return false;
1127 m_ptr_size = process_sp->GetAddressByteSize();
1128 m_order = process_sp->GetByteOrder();
1129 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1130 if (m_ptr_size == 4) {
1131 m_data_32 = new DataDescriptor_32();
1132 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
1133 error);
1134 } else {
1135 m_data_64 = new DataDescriptor_64();
1136 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
1137 error);
1138 }
1139 if (error.Fail())
1140 return false;
1141 return false;
1142 }
1143
1144 bool
1145 lldb_private::formatters::Foundation1100::
MightHaveChildren()1146 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
1147 return true;
1148 }
1149
1150 lldb::ValueObjectSP
1151 lldb_private::formatters::Foundation1100::
GetChildAtIndex(size_t idx)1152 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
1153 lldb::addr_t m_keys_ptr =
1154 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
1155 lldb::addr_t m_values_ptr =
1156 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
1157
1158 uint32_t num_children = CalculateNumChildren();
1159
1160 if (idx >= num_children)
1161 return lldb::ValueObjectSP();
1162
1163 if (m_children.empty()) {
1164 // do the scan phase
1165 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1166
1167 uint32_t tries = 0;
1168 uint32_t test_idx = 0;
1169
1170 while (tries < num_children) {
1171 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1172 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1173 ;
1174 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1175 if (!process_sp)
1176 return lldb::ValueObjectSP();
1177 Status error;
1178 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1179 if (error.Fail())
1180 return lldb::ValueObjectSP();
1181 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1182 if (error.Fail())
1183 return lldb::ValueObjectSP();
1184
1185 test_idx++;
1186
1187 if (!key_at_idx || !val_at_idx)
1188 continue;
1189 tries++;
1190
1191 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1192 lldb::ValueObjectSP()};
1193
1194 m_children.push_back(descriptor);
1195 }
1196 }
1197
1198 if (idx >= m_children.size()) // should never happen
1199 return lldb::ValueObjectSP();
1200
1201 DictionaryItemDescriptor &dict_item = m_children[idx];
1202 if (!dict_item.valobj_sp) {
1203 if (!m_pair_type.IsValid()) {
1204 TargetSP target_sp(m_backend.GetTargetSP());
1205 if (!target_sp)
1206 return ValueObjectSP();
1207 m_pair_type = GetLLDBNSPairType(target_sp);
1208 }
1209 if (!m_pair_type.IsValid())
1210 return ValueObjectSP();
1211
1212 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1213
1214 if (m_ptr_size == 8) {
1215 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1216 *data_ptr = dict_item.key_ptr;
1217 *(data_ptr + 1) = dict_item.val_ptr;
1218 } else {
1219 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1220 *data_ptr = dict_item.key_ptr;
1221 *(data_ptr + 1) = dict_item.val_ptr;
1222 }
1223
1224 StreamString idx_name;
1225 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1226 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1227 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1228 m_exe_ctx_ref, m_pair_type);
1229 }
1230 return dict_item.valobj_sp;
1231 }
1232
1233 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(
1234 ValueObject &, Stream &, const TypeSummaryOptions &);
1235
1236 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(
1237 ValueObject &, Stream &, const TypeSummaryOptions &);
1238