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