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