Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
39644 views
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
34
NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
35
ConstString p)
36
: m_prefix(p) {}
37
38
bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(
39
ConstString class_name) {
40
return class_name.GetStringRef().starts_with(m_prefix.GetStringRef());
41
}
42
43
NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)
44
: m_name(n) {}
45
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> &
53
NSDictionary_Additionals::GetAdditionalSummaries() {
54
static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map;
55
return g_map;
56
}
57
58
NSDictionary_Additionals::AdditionalFormatters<
59
CXXSyntheticChildren::CreateFrontEndCallback> &
60
NSDictionary_Additionals::GetAdditionalSynthetics() {
61
static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback>
62
g_map;
63
return g_map;
64
}
65
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
llvm::Expected<uint32_t> CalculateNumChildren() override;
107
108
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
109
110
lldb::ChildCacheState 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
llvm::Expected<uint32_t> CalculateNumChildren() override;
148
149
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
150
151
lldb::ChildCacheState 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
llvm::Expected<uint32_t> CalculateNumChildren() override;
180
181
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
182
183
lldb::ChildCacheState 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
llvm::Expected<uint32_t> CalculateNumChildren() override;
213
214
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
215
216
lldb::ChildCacheState 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
llvm::Expected<uint32_t> CalculateNumChildren() override;
234
235
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
236
237
lldb::ChildCacheState 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
llvm::Expected<uint32_t> CalculateNumChildren() override;
267
268
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
269
270
lldb::ChildCacheState 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;
318
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;
326
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
354
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
367
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
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
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>
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 *
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::
589
NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
590
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
591
592
lldb_private::formatters::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::
601
GetIndexOfChildWithName(ConstString name) {
602
const char *item_name = name.GetCString();
603
uint32_t idx = ExtractIndexFromString(item_name);
604
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
605
return UINT32_MAX;
606
return idx;
607
}
608
609
llvm::Expected<uint32_t> lldb_private::formatters::
610
NSDictionaryISyntheticFrontEnd::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
616
lldb::ChildCacheState
617
lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
618
m_children.clear();
619
delete m_data_32;
620
m_data_32 = nullptr;
621
delete m_data_64;
622
m_data_64 = nullptr;
623
m_ptr_size = 0;
624
ValueObjectSP valobj_sp = m_backend.GetSP();
625
if (!valobj_sp)
626
return lldb::ChildCacheState::eRefetch;
627
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
628
Status error;
629
error.Clear();
630
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
631
if (!process_sp)
632
return lldb::ChildCacheState::eRefetch;
633
m_ptr_size = process_sp->GetAddressByteSize();
634
m_order = process_sp->GetByteOrder();
635
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
636
if (m_ptr_size == 4) {
637
m_data_32 = new DataDescriptor_32();
638
process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
639
error);
640
} else {
641
m_data_64 = new DataDescriptor_64();
642
process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
643
error);
644
}
645
if (error.Fail())
646
return lldb::ChildCacheState::eRefetch;
647
m_data_ptr = data_location + m_ptr_size;
648
return lldb::ChildCacheState::eRefetch;
649
}
650
651
bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
652
MightHaveChildren() {
653
return true;
654
}
655
656
lldb::ValueObjectSP
657
lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
658
uint32_t idx) {
659
uint32_t num_children = CalculateNumChildrenIgnoringErrors();
660
661
if (idx >= num_children)
662
return lldb::ValueObjectSP();
663
664
if (m_children.empty()) {
665
// do the scan phase
666
lldb::addr_t key_at_idx = 0, val_at_idx = 0;
667
668
uint32_t tries = 0;
669
uint32_t test_idx = 0;
670
671
while (tries < num_children) {
672
key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
673
val_at_idx = key_at_idx + m_ptr_size;
674
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
675
if (!process_sp)
676
return lldb::ValueObjectSP();
677
Status error;
678
key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
679
if (error.Fail())
680
return lldb::ValueObjectSP();
681
val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
682
if (error.Fail())
683
return lldb::ValueObjectSP();
684
685
test_idx++;
686
687
if (!key_at_idx || !val_at_idx)
688
continue;
689
tries++;
690
691
DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
692
lldb::ValueObjectSP()};
693
694
m_children.push_back(descriptor);
695
}
696
}
697
698
if (idx >= m_children.size()) // should never happen
699
return lldb::ValueObjectSP();
700
701
DictionaryItemDescriptor &dict_item = m_children[idx];
702
if (!dict_item.valobj_sp) {
703
if (!m_pair_type.IsValid()) {
704
TargetSP target_sp(m_backend.GetTargetSP());
705
if (!target_sp)
706
return ValueObjectSP();
707
m_pair_type = GetLLDBNSPairType(target_sp);
708
}
709
if (!m_pair_type.IsValid())
710
return ValueObjectSP();
711
712
WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
713
714
if (m_ptr_size == 8) {
715
uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
716
*data_ptr = dict_item.key_ptr;
717
*(data_ptr + 1) = dict_item.val_ptr;
718
} else {
719
uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
720
*data_ptr = dict_item.key_ptr;
721
*(data_ptr + 1) = dict_item.val_ptr;
722
}
723
724
StreamString idx_name;
725
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
726
DataExtractor data(buffer_sp, m_order, m_ptr_size);
727
dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
728
m_exe_ctx_ref, m_pair_type);
729
}
730
return dict_item.valobj_sp;
731
}
732
733
lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
734
NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
735
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),
736
m_pair_type() {}
737
738
size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
739
GetIndexOfChildWithName(ConstString name) {
740
const char *item_name = name.GetCString();
741
const uint32_t idx = ExtractIndexFromString(item_name);
742
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
743
return UINT32_MAX;
744
return idx;
745
}
746
747
llvm::Expected<uint32_t> lldb_private::formatters::
748
NSCFDictionarySyntheticFrontEnd::CalculateNumChildren() {
749
if (!m_hashtable.IsValid())
750
return 0;
751
return m_hashtable.GetCount();
752
}
753
754
lldb::ChildCacheState
755
lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {
756
m_children.clear();
757
ValueObjectSP valobj_sp = m_backend.GetSP();
758
m_ptr_size = 0;
759
if (!valobj_sp)
760
return lldb::ChildCacheState::eRefetch;
761
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
762
763
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
764
if (!process_sp)
765
return lldb::ChildCacheState::eRefetch;
766
m_ptr_size = process_sp->GetAddressByteSize();
767
m_order = process_sp->GetByteOrder();
768
return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)
769
? lldb::ChildCacheState::eReuse
770
: lldb::ChildCacheState::eRefetch;
771
}
772
773
bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
774
MightHaveChildren() {
775
return true;
776
}
777
778
lldb::ValueObjectSP
779
lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
780
uint32_t idx) {
781
lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer();
782
lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
783
784
const uint32_t num_children = CalculateNumChildrenIgnoringErrors();
785
786
if (idx >= num_children)
787
return lldb::ValueObjectSP();
788
789
if (m_children.empty()) {
790
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
791
if (!process_sp)
792
return lldb::ValueObjectSP();
793
794
Status error;
795
lldb::addr_t key_at_idx = 0, val_at_idx = 0;
796
797
uint32_t tries = 0;
798
uint32_t test_idx = 0;
799
800
// Iterate over inferior memory, reading key/value pointers by shifting each
801
// cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
802
// fails, otherwise, continue until the number of tries matches the number
803
// of childen.
804
while (tries < num_children) {
805
key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
806
val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
807
808
key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
809
if (error.Fail())
810
return lldb::ValueObjectSP();
811
val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
812
if (error.Fail())
813
return lldb::ValueObjectSP();
814
815
test_idx++;
816
817
if (!key_at_idx || !val_at_idx)
818
continue;
819
tries++;
820
821
DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
822
lldb::ValueObjectSP()};
823
824
m_children.push_back(descriptor);
825
}
826
}
827
828
if (idx >= m_children.size()) // should never happen
829
return lldb::ValueObjectSP();
830
831
DictionaryItemDescriptor &dict_item = m_children[idx];
832
if (!dict_item.valobj_sp) {
833
if (!m_pair_type.IsValid()) {
834
TargetSP target_sp(m_backend.GetTargetSP());
835
if (!target_sp)
836
return ValueObjectSP();
837
m_pair_type = GetLLDBNSPairType(target_sp);
838
}
839
if (!m_pair_type.IsValid())
840
return ValueObjectSP();
841
842
WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
843
844
switch (m_ptr_size) {
845
case 0: // architecture has no clue - fail
846
return lldb::ValueObjectSP();
847
case 4: {
848
uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes());
849
*data_ptr = dict_item.key_ptr;
850
*(data_ptr + 1) = dict_item.val_ptr;
851
} break;
852
case 8: {
853
uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes());
854
*data_ptr = dict_item.key_ptr;
855
*(data_ptr + 1) = dict_item.val_ptr;
856
} break;
857
default:
858
lldbassert(false && "pointer size is not 4 nor 8");
859
}
860
861
StreamString idx_name;
862
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
863
DataExtractor data(buffer_sp, m_order, m_ptr_size);
864
dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
865
m_exe_ctx_ref, m_pair_type);
866
}
867
return dict_item.valobj_sp;
868
}
869
870
lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
871
NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
872
: SyntheticChildrenFrontEnd(*valobj_sp) {}
873
874
size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
875
GetIndexOfChildWithName(ConstString name) {
876
const char *item_name = name.GetCString();
877
uint32_t idx = ExtractIndexFromString(item_name);
878
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
879
return UINT32_MAX;
880
return idx;
881
}
882
883
llvm::Expected<uint32_t> lldb_private::formatters::
884
NSConstantDictionarySyntheticFrontEnd::CalculateNumChildren() {
885
return m_size;
886
}
887
888
lldb::ChildCacheState
889
lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() {
890
ValueObjectSP valobj_sp = m_backend.GetSP();
891
if (!valobj_sp)
892
return lldb::ChildCacheState::eRefetch;
893
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
894
Status error;
895
error.Clear();
896
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
897
if (!process_sp)
898
return lldb::ChildCacheState::eRefetch;
899
m_ptr_size = process_sp->GetAddressByteSize();
900
m_order = process_sp->GetByteOrder();
901
uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0);
902
m_size = process_sp->ReadUnsignedIntegerFromMemory(
903
valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error);
904
if (error.Fail())
905
return lldb::ChildCacheState::eRefetch;
906
m_keys_ptr =
907
process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size, error);
908
if (error.Fail())
909
return lldb::ChildCacheState::eRefetch;
910
m_objects_ptr =
911
process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size, error);
912
913
return error.Success() ? lldb::ChildCacheState::eReuse
914
: lldb::ChildCacheState::eRefetch;
915
}
916
917
bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
918
MightHaveChildren() {
919
return true;
920
}
921
922
lldb::ValueObjectSP lldb_private::formatters::
923
NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
924
uint32_t num_children = CalculateNumChildrenIgnoringErrors();
925
926
if (idx >= num_children)
927
return lldb::ValueObjectSP();
928
929
if (m_children.empty()) {
930
// do the scan phase
931
lldb::addr_t key_at_idx = 0, val_at_idx = 0;
932
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
933
if (!process_sp)
934
return lldb::ValueObjectSP();
935
936
for (unsigned int child = 0; child < num_children; ++child) {
937
Status error;
938
key_at_idx = process_sp->ReadPointerFromMemory(
939
m_keys_ptr + child * m_ptr_size, error);
940
if (error.Fail())
941
return lldb::ValueObjectSP();
942
val_at_idx = process_sp->ReadPointerFromMemory(
943
m_objects_ptr + child * m_ptr_size, error);
944
if (error.Fail())
945
return lldb::ValueObjectSP();
946
DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
947
lldb::ValueObjectSP()};
948
m_children.push_back(descriptor);
949
}
950
}
951
952
if (idx >= m_children.size()) // should never happen
953
return lldb::ValueObjectSP();
954
955
DictionaryItemDescriptor &dict_item = m_children[idx];
956
if (!dict_item.valobj_sp) {
957
if (!m_pair_type.IsValid()) {
958
TargetSP target_sp(m_backend.GetTargetSP());
959
if (!target_sp)
960
return ValueObjectSP();
961
m_pair_type = GetLLDBNSPairType(target_sp);
962
}
963
if (!m_pair_type.IsValid())
964
return ValueObjectSP();
965
966
WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
967
968
if (m_ptr_size == 8) {
969
uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
970
*data_ptr = dict_item.key_ptr;
971
*(data_ptr + 1) = dict_item.val_ptr;
972
} else {
973
uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
974
*data_ptr = dict_item.key_ptr;
975
*(data_ptr + 1) = dict_item.val_ptr;
976
}
977
978
StreamString idx_name;
979
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
980
DataExtractor data(buffer_sp, m_order, m_ptr_size);
981
dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
982
m_exe_ctx_ref, m_pair_type);
983
}
984
return dict_item.valobj_sp;
985
}
986
987
lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
988
NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
989
: SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
990
991
size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
992
GetIndexOfChildWithName(ConstString name) {
993
static const ConstString g_zero("[0]");
994
return name == g_zero ? 0 : UINT32_MAX;
995
}
996
997
llvm::Expected<uint32_t> lldb_private::formatters::
998
NSDictionary1SyntheticFrontEnd::CalculateNumChildren() {
999
return 1;
1000
}
1001
1002
lldb::ChildCacheState
1003
lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
1004
m_pair.reset();
1005
return lldb::ChildCacheState::eRefetch;
1006
}
1007
1008
bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
1009
MightHaveChildren() {
1010
return true;
1011
}
1012
1013
lldb::ValueObjectSP
1014
lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
1015
uint32_t idx) {
1016
if (idx != 0)
1017
return lldb::ValueObjectSP();
1018
1019
if (m_pair.get())
1020
return m_pair;
1021
1022
auto process_sp(m_backend.GetProcessSP());
1023
if (!process_sp)
1024
return nullptr;
1025
1026
auto ptr_size = process_sp->GetAddressByteSize();
1027
1028
lldb::addr_t key_ptr =
1029
m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
1030
lldb::addr_t value_ptr = key_ptr + ptr_size;
1031
1032
Status error;
1033
1034
lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
1035
if (error.Fail())
1036
return nullptr;
1037
lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
1038
if (error.Fail())
1039
return nullptr;
1040
1041
auto pair_type =
1042
GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
1043
1044
WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
1045
1046
if (ptr_size == 8) {
1047
uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1048
*data_ptr = key_at_idx;
1049
*(data_ptr + 1) = value_at_idx;
1050
} else {
1051
uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1052
*data_ptr = key_at_idx;
1053
*(data_ptr + 1) = value_at_idx;
1054
}
1055
1056
DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
1057
m_pair = CreateValueObjectFromData(
1058
"[0]", data, m_backend.GetExecutionContextRef(), pair_type);
1059
1060
return m_pair;
1061
}
1062
1063
template <typename D32, typename D64>
1064
lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32, D64>::
1065
GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
1066
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
1067
m_data_32(nullptr), m_data_64(nullptr), m_pair_type() {}
1068
1069
template <typename D32, typename D64>
1070
lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
1071
D32, D64>::GenericNSDictionaryMSyntheticFrontEnd::
1072
~GenericNSDictionaryMSyntheticFrontEnd() {
1073
delete m_data_32;
1074
m_data_32 = nullptr;
1075
delete m_data_64;
1076
m_data_64 = nullptr;
1077
}
1078
1079
template <typename D32, typename D64>
1080
size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
1081
D32, D64>::GetIndexOfChildWithName(ConstString name) {
1082
const char *item_name = name.GetCString();
1083
uint32_t idx = ExtractIndexFromString(item_name);
1084
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
1085
return UINT32_MAX;
1086
return idx;
1087
}
1088
1089
template <typename D32, typename D64>
1090
llvm::Expected<uint32_t>
1091
lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
1092
D32, D64>::CalculateNumChildren() {
1093
if (!m_data_32 && !m_data_64)
1094
return 0;
1095
return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);
1096
}
1097
1098
template <typename D32, typename D64>
1099
lldb::ChildCacheState
1100
lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,
1101
D64>::Update() {
1102
m_children.clear();
1103
ValueObjectSP valobj_sp = m_backend.GetSP();
1104
m_ptr_size = 0;
1105
delete m_data_32;
1106
m_data_32 = nullptr;
1107
delete m_data_64;
1108
m_data_64 = nullptr;
1109
if (!valobj_sp)
1110
return lldb::ChildCacheState::eRefetch;
1111
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1112
Status error;
1113
error.Clear();
1114
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1115
if (!process_sp)
1116
return lldb::ChildCacheState::eRefetch;
1117
m_ptr_size = process_sp->GetAddressByteSize();
1118
m_order = process_sp->GetByteOrder();
1119
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1120
if (m_ptr_size == 4) {
1121
m_data_32 = new D32();
1122
process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
1123
error);
1124
} else {
1125
m_data_64 = new D64();
1126
process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
1127
error);
1128
}
1129
1130
return error.Success() ? lldb::ChildCacheState::eReuse
1131
: lldb::ChildCacheState::eRefetch;
1132
}
1133
1134
template <typename D32, typename D64>
1135
bool
1136
lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
1137
MightHaveChildren() {
1138
return true;
1139
}
1140
1141
template <typename D32, typename D64>
1142
lldb::ValueObjectSP
1143
lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
1144
D32, D64>::GetChildAtIndex(uint32_t idx) {
1145
lldb::addr_t m_keys_ptr;
1146
lldb::addr_t m_values_ptr;
1147
if (m_data_32) {
1148
uint32_t size = m_data_32->GetSize();
1149
m_keys_ptr = m_data_32->_buffer;
1150
m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
1151
} else {
1152
uint32_t size = m_data_64->GetSize();
1153
m_keys_ptr = m_data_64->_buffer;
1154
m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
1155
}
1156
1157
uint32_t num_children = CalculateNumChildrenIgnoringErrors();
1158
1159
if (idx >= num_children)
1160
return lldb::ValueObjectSP();
1161
1162
if (m_children.empty()) {
1163
// do the scan phase
1164
lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1165
1166
uint32_t tries = 0;
1167
uint32_t test_idx = 0;
1168
1169
while (tries < num_children) {
1170
key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1171
val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1172
;
1173
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1174
if (!process_sp)
1175
return lldb::ValueObjectSP();
1176
Status error;
1177
key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1178
if (error.Fail())
1179
return lldb::ValueObjectSP();
1180
val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1181
if (error.Fail())
1182
return lldb::ValueObjectSP();
1183
1184
test_idx++;
1185
1186
if (!key_at_idx || !val_at_idx)
1187
continue;
1188
tries++;
1189
1190
DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1191
lldb::ValueObjectSP()};
1192
1193
m_children.push_back(descriptor);
1194
}
1195
}
1196
1197
if (idx >= m_children.size()) // should never happen
1198
return lldb::ValueObjectSP();
1199
1200
DictionaryItemDescriptor &dict_item = m_children[idx];
1201
if (!dict_item.valobj_sp) {
1202
if (!m_pair_type.IsValid()) {
1203
TargetSP target_sp(m_backend.GetTargetSP());
1204
if (!target_sp)
1205
return ValueObjectSP();
1206
m_pair_type = GetLLDBNSPairType(target_sp);
1207
}
1208
if (!m_pair_type.IsValid())
1209
return ValueObjectSP();
1210
1211
WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1212
1213
if (m_ptr_size == 8) {
1214
uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1215
*data_ptr = dict_item.key_ptr;
1216
*(data_ptr + 1) = dict_item.val_ptr;
1217
} else {
1218
uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1219
*data_ptr = dict_item.key_ptr;
1220
*(data_ptr + 1) = dict_item.val_ptr;
1221
}
1222
1223
StreamString idx_name;
1224
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1225
DataExtractor data(buffer_sp, m_order, m_ptr_size);
1226
dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1227
m_exe_ctx_ref, m_pair_type);
1228
}
1229
return dict_item.valobj_sp;
1230
}
1231
1232
lldb_private::formatters::Foundation1100::NSDictionaryMSyntheticFrontEnd::
1233
NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
1234
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
1235
1236
lldb_private::formatters::Foundation1100::
1237
NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {
1238
delete m_data_32;
1239
m_data_32 = nullptr;
1240
delete m_data_64;
1241
m_data_64 = nullptr;
1242
}
1243
1244
size_t
1245
lldb_private::formatters::Foundation1100::
1246
NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
1247
const char *item_name = name.GetCString();
1248
uint32_t idx = ExtractIndexFromString(item_name);
1249
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
1250
return UINT32_MAX;
1251
return idx;
1252
}
1253
1254
llvm::Expected<uint32_t> lldb_private::formatters::Foundation1100::
1255
NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
1256
if (!m_data_32 && !m_data_64)
1257
return 0;
1258
return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1259
}
1260
1261
lldb::ChildCacheState lldb_private::formatters::Foundation1100::
1262
NSDictionaryMSyntheticFrontEnd::Update() {
1263
m_children.clear();
1264
ValueObjectSP valobj_sp = m_backend.GetSP();
1265
m_ptr_size = 0;
1266
delete m_data_32;
1267
m_data_32 = nullptr;
1268
delete m_data_64;
1269
m_data_64 = nullptr;
1270
if (!valobj_sp)
1271
return lldb::ChildCacheState::eRefetch;
1272
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1273
Status error;
1274
error.Clear();
1275
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1276
if (!process_sp)
1277
return lldb::ChildCacheState::eRefetch;
1278
m_ptr_size = process_sp->GetAddressByteSize();
1279
m_order = process_sp->GetByteOrder();
1280
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1281
if (m_ptr_size == 4) {
1282
m_data_32 = new DataDescriptor_32();
1283
process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
1284
error);
1285
} else {
1286
m_data_64 = new DataDescriptor_64();
1287
process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
1288
error);
1289
}
1290
1291
return error.Success() ? lldb::ChildCacheState::eReuse
1292
: lldb::ChildCacheState::eRefetch;
1293
}
1294
1295
bool
1296
lldb_private::formatters::Foundation1100::
1297
NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
1298
return true;
1299
}
1300
1301
lldb::ValueObjectSP
1302
lldb_private::formatters::Foundation1100::
1303
NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
1304
lldb::addr_t m_keys_ptr =
1305
(m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
1306
lldb::addr_t m_values_ptr =
1307
(m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
1308
1309
uint32_t num_children = CalculateNumChildrenIgnoringErrors();
1310
1311
if (idx >= num_children)
1312
return lldb::ValueObjectSP();
1313
1314
if (m_children.empty()) {
1315
// do the scan phase
1316
lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1317
1318
uint32_t tries = 0;
1319
uint32_t test_idx = 0;
1320
1321
while (tries < num_children) {
1322
key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1323
val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1324
;
1325
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1326
if (!process_sp)
1327
return lldb::ValueObjectSP();
1328
Status error;
1329
key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1330
if (error.Fail())
1331
return lldb::ValueObjectSP();
1332
val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1333
if (error.Fail())
1334
return lldb::ValueObjectSP();
1335
1336
test_idx++;
1337
1338
if (!key_at_idx || !val_at_idx)
1339
continue;
1340
tries++;
1341
1342
DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1343
lldb::ValueObjectSP()};
1344
1345
m_children.push_back(descriptor);
1346
}
1347
}
1348
1349
if (idx >= m_children.size()) // should never happen
1350
return lldb::ValueObjectSP();
1351
1352
DictionaryItemDescriptor &dict_item = m_children[idx];
1353
if (!dict_item.valobj_sp) {
1354
if (!m_pair_type.IsValid()) {
1355
TargetSP target_sp(m_backend.GetTargetSP());
1356
if (!target_sp)
1357
return ValueObjectSP();
1358
m_pair_type = GetLLDBNSPairType(target_sp);
1359
}
1360
if (!m_pair_type.IsValid())
1361
return ValueObjectSP();
1362
1363
WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1364
1365
if (m_ptr_size == 8) {
1366
uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1367
*data_ptr = dict_item.key_ptr;
1368
*(data_ptr + 1) = dict_item.val_ptr;
1369
} else {
1370
uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1371
*data_ptr = dict_item.key_ptr;
1372
*(data_ptr + 1) = dict_item.val_ptr;
1373
}
1374
1375
StreamString idx_name;
1376
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1377
DataExtractor data(buffer_sp, m_order, m_ptr_size);
1378
dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1379
m_exe_ctx_ref, m_pair_type);
1380
}
1381
return dict_item.valobj_sp;
1382
}
1383
1384
template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(
1385
ValueObject &, Stream &, const TypeSummaryOptions &);
1386
1387
template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(
1388
ValueObject &, Stream &, const TypeSummaryOptions &);
1389
1390