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