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