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/NSSet.cpp
39644 views
1
//===-- NSSet.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 "NSSet.h"
10
#include "CFBasicHash.h"
11
12
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
13
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
14
#include "lldb/Core/ValueObject.h"
15
#include "lldb/Core/ValueObjectConstResult.h"
16
#include "lldb/DataFormatters/FormattersHelpers.h"
17
#include "lldb/Target/Language.h"
18
#include "lldb/Target/Target.h"
19
#include "lldb/Utility/DataBufferHeap.h"
20
#include "lldb/Utility/Endian.h"
21
#include "lldb/Utility/Status.h"
22
#include "lldb/Utility/Stream.h"
23
24
using namespace lldb;
25
using namespace lldb_private;
26
using namespace lldb_private::formatters;
27
28
std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
29
NSSet_Additionals::GetAdditionalSummaries() {
30
static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
31
return g_map;
32
}
33
34
std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
35
NSSet_Additionals::GetAdditionalSynthetics() {
36
static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
37
g_map;
38
return g_map;
39
}
40
41
namespace lldb_private {
42
namespace formatters {
43
class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
44
public:
45
NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
46
47
~NSSetISyntheticFrontEnd() override;
48
49
llvm::Expected<uint32_t> CalculateNumChildren() override;
50
51
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
52
53
lldb::ChildCacheState Update() override;
54
55
bool MightHaveChildren() override;
56
57
size_t GetIndexOfChildWithName(ConstString name) override;
58
59
private:
60
struct DataDescriptor_32 {
61
uint32_t _used : 26;
62
uint32_t _szidx : 6;
63
};
64
65
struct DataDescriptor_64 {
66
uint64_t _used : 58;
67
uint32_t _szidx : 6;
68
};
69
70
struct SetItemDescriptor {
71
lldb::addr_t item_ptr;
72
lldb::ValueObjectSP valobj_sp;
73
};
74
75
ExecutionContextRef m_exe_ctx_ref;
76
uint8_t m_ptr_size = 8;
77
DataDescriptor_32 *m_data_32 = nullptr;
78
DataDescriptor_64 *m_data_64 = nullptr;
79
lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;
80
std::vector<SetItemDescriptor> m_children;
81
};
82
83
class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
84
public:
85
NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
86
87
llvm::Expected<uint32_t> CalculateNumChildren() override;
88
89
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
90
91
lldb::ChildCacheState Update() override;
92
93
bool MightHaveChildren() override;
94
95
size_t GetIndexOfChildWithName(ConstString name) override;
96
97
private:
98
struct SetItemDescriptor {
99
lldb::addr_t item_ptr;
100
lldb::ValueObjectSP valobj_sp;
101
};
102
103
ExecutionContextRef m_exe_ctx_ref;
104
uint8_t m_ptr_size = 8;
105
lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
106
107
CFBasicHash m_hashtable;
108
109
CompilerType m_pair_type;
110
std::vector<SetItemDescriptor> m_children;
111
};
112
113
template <typename D32, typename D64>
114
class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
115
public:
116
GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
117
118
~GenericNSSetMSyntheticFrontEnd() override;
119
120
llvm::Expected<uint32_t> CalculateNumChildren() override;
121
122
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
123
124
lldb::ChildCacheState Update() override;
125
126
bool MightHaveChildren() override;
127
128
size_t GetIndexOfChildWithName(ConstString name) override;
129
130
private:
131
132
struct SetItemDescriptor {
133
lldb::addr_t item_ptr;
134
lldb::ValueObjectSP valobj_sp;
135
};
136
137
ExecutionContextRef m_exe_ctx_ref;
138
uint8_t m_ptr_size = 8;
139
D32 *m_data_32;
140
D64 *m_data_64;
141
std::vector<SetItemDescriptor> m_children;
142
};
143
144
namespace Foundation1300 {
145
struct DataDescriptor_32 {
146
uint32_t _used : 26;
147
uint32_t _size;
148
uint32_t _mutations;
149
uint32_t _objs_addr;
150
};
151
152
struct DataDescriptor_64 {
153
uint64_t _used : 58;
154
uint64_t _size;
155
uint64_t _mutations;
156
uint64_t _objs_addr;
157
};
158
159
using NSSetMSyntheticFrontEnd =
160
GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
161
}
162
163
namespace Foundation1428 {
164
struct DataDescriptor_32 {
165
uint32_t _used : 26;
166
uint32_t _size;
167
uint32_t _objs_addr;
168
uint32_t _mutations;
169
};
170
171
struct DataDescriptor_64 {
172
uint64_t _used : 58;
173
uint64_t _size;
174
uint64_t _objs_addr;
175
uint64_t _mutations;
176
};
177
178
using NSSetMSyntheticFrontEnd =
179
GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
180
}
181
182
namespace Foundation1437 {
183
struct DataDescriptor_32 {
184
uint32_t _cow;
185
// __table storage
186
uint32_t _objs_addr;
187
uint32_t _muts;
188
uint32_t _used : 26;
189
uint32_t _szidx : 6;
190
};
191
192
struct DataDescriptor_64 {
193
uint64_t _cow;
194
// __Table storage
195
uint64_t _objs_addr;
196
uint32_t _muts;
197
uint32_t _used : 26;
198
uint32_t _szidx : 6;
199
};
200
201
using NSSetMSyntheticFrontEnd =
202
GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
203
204
template <typename DD>
205
uint64_t
206
__NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr,
207
Status &error) {
208
const lldb::addr_t start_of_descriptor =
209
valobj_addr + process.GetAddressByteSize();
210
DD descriptor = DD();
211
process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
212
error);
213
if (error.Fail()) {
214
return 0;
215
}
216
return descriptor._used;
217
}
218
219
uint64_t
220
__NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
221
Status &error) {
222
if (process.GetAddressByteSize() == 4) {
223
return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error);
224
} else {
225
return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error);
226
}
227
}
228
}
229
230
class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
231
public:
232
NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
233
234
~NSSetCodeRunningSyntheticFrontEnd() override;
235
236
llvm::Expected<uint32_t> CalculateNumChildren() override;
237
238
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
239
240
lldb::ChildCacheState Update() override;
241
242
bool MightHaveChildren() override;
243
244
size_t GetIndexOfChildWithName(ConstString name) override;
245
};
246
} // namespace formatters
247
} // namespace lldb_private
248
249
template <bool cf_style>
250
bool lldb_private::formatters::NSSetSummaryProvider(
251
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
252
static constexpr llvm::StringLiteral g_TypeHint("NSSet");
253
254
ProcessSP process_sp = valobj.GetProcessSP();
255
if (!process_sp)
256
return false;
257
258
ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
259
260
if (!runtime)
261
return false;
262
263
ObjCLanguageRuntime::ClassDescriptorSP descriptor(
264
runtime->GetClassDescriptor(valobj));
265
266
if (!descriptor || !descriptor->IsValid())
267
return false;
268
269
uint32_t ptr_size = process_sp->GetAddressByteSize();
270
bool is_64bit = (ptr_size == 8);
271
272
lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
273
274
if (!valobj_addr)
275
return false;
276
277
uint64_t value = 0;
278
279
ConstString class_name(descriptor->GetClassName());
280
281
static const ConstString g_SetI("__NSSetI");
282
static const ConstString g_OrderedSetI("__NSOrderedSetI");
283
static const ConstString g_SetM("__NSSetM");
284
static const ConstString g_SetCF("__NSCFSet");
285
static const ConstString g_SetCFRef("CFSetRef");
286
287
if (class_name.IsEmpty())
288
return false;
289
290
if (class_name == g_SetI || class_name == g_OrderedSetI) {
291
Status error;
292
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
293
ptr_size, 0, error);
294
if (error.Fail())
295
return false;
296
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
297
} else if (class_name == g_SetM) {
298
AppleObjCRuntime *apple_runtime =
299
llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
300
Status error;
301
if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
302
value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error);
303
} else {
304
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
305
ptr_size, 0, error);
306
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
307
}
308
if (error.Fail())
309
return false;
310
} else if (class_name == g_SetCF || class_name == g_SetCFRef) {
311
ExecutionContext exe_ctx(process_sp);
312
CFBasicHash cfbh;
313
if (!cfbh.Update(valobj_addr, exe_ctx))
314
return false;
315
value = cfbh.GetCount();
316
} else {
317
auto &map(NSSet_Additionals::GetAdditionalSummaries());
318
auto iter = map.find(class_name), end = map.end();
319
if (iter != end)
320
return iter->second(valobj, stream, options);
321
else
322
return false;
323
}
324
325
llvm::StringRef prefix, suffix;
326
if (Language *language = Language::FindPlugin(options.GetLanguage()))
327
std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
328
329
stream << prefix;
330
stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");
331
stream << suffix;
332
return true;
333
}
334
335
SyntheticChildrenFrontEnd *
336
lldb_private::formatters::NSSetSyntheticFrontEndCreator(
337
CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
338
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
339
if (!process_sp)
340
return nullptr;
341
ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
342
if (!runtime)
343
return nullptr;
344
345
CompilerType valobj_type(valobj_sp->GetCompilerType());
346
Flags flags(valobj_type.GetTypeInfo());
347
348
if (flags.IsClear(eTypeIsPointer)) {
349
Status error;
350
valobj_sp = valobj_sp->AddressOf(error);
351
if (error.Fail() || !valobj_sp)
352
return nullptr;
353
}
354
355
ObjCLanguageRuntime::ClassDescriptorSP descriptor(
356
runtime->GetClassDescriptor(*valobj_sp));
357
358
if (!descriptor || !descriptor->IsValid())
359
return nullptr;
360
361
ConstString class_name = descriptor->GetClassName();
362
363
static const ConstString g_SetI("__NSSetI");
364
static const ConstString g_OrderedSetI("__NSOrderedSetI");
365
static const ConstString g_SetM("__NSSetM");
366
static const ConstString g_SetCF("__NSCFSet");
367
static const ConstString g_SetCFRef("CFSetRef");
368
369
if (class_name.IsEmpty())
370
return nullptr;
371
372
if (class_name == g_SetI || class_name == g_OrderedSetI) {
373
return (new NSSetISyntheticFrontEnd(valobj_sp));
374
} else if (class_name == g_SetM) {
375
AppleObjCRuntime *apple_runtime =
376
llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
377
if (apple_runtime) {
378
if (apple_runtime->GetFoundationVersion() >= 1437)
379
return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp));
380
else if (apple_runtime->GetFoundationVersion() >= 1428)
381
return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp));
382
else
383
return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
384
} else {
385
return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
386
}
387
} else if (class_name == g_SetCF || class_name == g_SetCFRef) {
388
return (new NSCFSetSyntheticFrontEnd(valobj_sp));
389
} else {
390
auto &map(NSSet_Additionals::GetAdditionalSynthetics());
391
auto iter = map.find(class_name), end = map.end();
392
if (iter != end)
393
return iter->second(synth, valobj_sp);
394
return nullptr;
395
}
396
}
397
398
lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(
399
lldb::ValueObjectSP valobj_sp)
400
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref() {
401
if (valobj_sp)
402
Update();
403
}
404
405
lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {
406
delete m_data_32;
407
m_data_32 = nullptr;
408
delete m_data_64;
409
m_data_64 = nullptr;
410
}
411
412
size_t
413
lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(
414
ConstString name) {
415
const char *item_name = name.GetCString();
416
uint32_t idx = ExtractIndexFromString(item_name);
417
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
418
return UINT32_MAX;
419
return idx;
420
}
421
422
llvm::Expected<uint32_t>
423
lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {
424
if (!m_data_32 && !m_data_64)
425
return 0;
426
return (m_data_32 ? m_data_32->_used : m_data_64->_used);
427
}
428
429
lldb::ChildCacheState
430
lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
431
m_children.clear();
432
delete m_data_32;
433
m_data_32 = nullptr;
434
delete m_data_64;
435
m_data_64 = nullptr;
436
m_ptr_size = 0;
437
ValueObjectSP valobj_sp = m_backend.GetSP();
438
if (!valobj_sp)
439
return lldb::ChildCacheState::eRefetch;
440
if (!valobj_sp)
441
return lldb::ChildCacheState::eRefetch;
442
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
443
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
444
if (!process_sp)
445
return lldb::ChildCacheState::eRefetch;
446
m_ptr_size = process_sp->GetAddressByteSize();
447
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
448
Status error;
449
if (m_ptr_size == 4) {
450
m_data_32 = new DataDescriptor_32();
451
process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
452
error);
453
} else {
454
m_data_64 = new DataDescriptor_64();
455
process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
456
error);
457
}
458
if (error.Fail())
459
return lldb::ChildCacheState::eRefetch;
460
m_data_ptr = data_location + m_ptr_size;
461
return lldb::ChildCacheState::eReuse;
462
}
463
464
bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() {
465
return true;
466
}
467
468
lldb::ValueObjectSP
469
lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(
470
uint32_t idx) {
471
uint32_t num_children = CalculateNumChildrenIgnoringErrors();
472
473
if (idx >= num_children)
474
return lldb::ValueObjectSP();
475
476
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
477
if (!process_sp)
478
return lldb::ValueObjectSP();
479
480
if (m_children.empty()) {
481
// do the scan phase
482
lldb::addr_t obj_at_idx = 0;
483
484
uint32_t tries = 0;
485
uint32_t test_idx = 0;
486
487
while (tries < num_children) {
488
obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
489
if (!process_sp)
490
return lldb::ValueObjectSP();
491
Status error;
492
obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
493
if (error.Fail())
494
return lldb::ValueObjectSP();
495
496
test_idx++;
497
498
if (!obj_at_idx)
499
continue;
500
tries++;
501
502
SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
503
504
m_children.push_back(descriptor);
505
}
506
}
507
508
if (idx >= m_children.size()) // should never happen
509
return lldb::ValueObjectSP();
510
511
SetItemDescriptor &set_item = m_children[idx];
512
if (!set_item.valobj_sp) {
513
auto ptr_size = process_sp->GetAddressByteSize();
514
DataBufferHeap buffer(ptr_size, 0);
515
switch (ptr_size) {
516
case 0: // architecture has no clue - fail
517
return lldb::ValueObjectSP();
518
case 4:
519
*reinterpret_cast<uint32_t *>(buffer.GetBytes()) =
520
static_cast<uint32_t>(set_item.item_ptr);
521
break;
522
case 8:
523
*reinterpret_cast<uint64_t *>(buffer.GetBytes()) =
524
static_cast<uint64_t>(set_item.item_ptr);
525
break;
526
default:
527
lldbassert(false && "pointer size is not 4 nor 8");
528
}
529
StreamString idx_name;
530
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
531
532
DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
533
process_sp->GetByteOrder(),
534
process_sp->GetAddressByteSize());
535
536
set_item.valobj_sp = CreateValueObjectFromData(
537
idx_name.GetString(), data, m_exe_ctx_ref,
538
m_backend.GetCompilerType().GetBasicTypeFromAST(
539
lldb::eBasicTypeObjCID));
540
}
541
return set_item.valobj_sp;
542
}
543
544
lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(
545
lldb::ValueObjectSP valobj_sp)
546
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),
547
m_pair_type() {}
548
549
size_t
550
lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName(
551
ConstString name) {
552
const char *item_name = name.GetCString();
553
const uint32_t idx = ExtractIndexFromString(item_name);
554
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
555
return UINT32_MAX;
556
return idx;
557
}
558
559
llvm::Expected<uint32_t>
560
lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {
561
if (!m_hashtable.IsValid())
562
return 0;
563
return m_hashtable.GetCount();
564
}
565
566
lldb::ChildCacheState
567
lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() {
568
m_children.clear();
569
ValueObjectSP valobj_sp = m_backend.GetSP();
570
m_ptr_size = 0;
571
if (!valobj_sp)
572
return lldb::ChildCacheState::eRefetch;
573
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
574
575
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
576
if (!process_sp)
577
return lldb::ChildCacheState::eRefetch;
578
m_ptr_size = process_sp->GetAddressByteSize();
579
m_order = process_sp->GetByteOrder();
580
return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)
581
? lldb::ChildCacheState::eReuse
582
: lldb::ChildCacheState::eRefetch;
583
}
584
585
bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() {
586
return true;
587
}
588
589
lldb::ValueObjectSP
590
lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(
591
uint32_t idx) {
592
lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
593
594
const uint32_t num_children = CalculateNumChildrenIgnoringErrors();
595
596
if (idx >= num_children)
597
return lldb::ValueObjectSP();
598
599
if (m_children.empty()) {
600
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
601
if (!process_sp)
602
return lldb::ValueObjectSP();
603
604
Status error;
605
lldb::addr_t val_at_idx = 0;
606
607
uint32_t tries = 0;
608
uint32_t test_idx = 0;
609
610
// Iterate over inferior memory, reading value pointers by shifting the
611
// cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
612
// fails, otherwise, continue until the number of tries matches the number
613
// of childen.
614
while (tries < num_children) {
615
val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
616
617
val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
618
if (error.Fail())
619
return lldb::ValueObjectSP();
620
621
test_idx++;
622
623
if (!val_at_idx)
624
continue;
625
tries++;
626
627
SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()};
628
629
m_children.push_back(descriptor);
630
}
631
}
632
633
if (idx >= m_children.size()) // should never happen
634
return lldb::ValueObjectSP();
635
636
SetItemDescriptor &set_item = m_children[idx];
637
if (!set_item.valobj_sp) {
638
639
WritableDataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0));
640
641
switch (m_ptr_size) {
642
case 0: // architecture has no clue - fail
643
return lldb::ValueObjectSP();
644
case 4:
645
*reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) =
646
static_cast<uint32_t>(set_item.item_ptr);
647
break;
648
case 8:
649
*reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) =
650
static_cast<uint64_t>(set_item.item_ptr);
651
break;
652
default:
653
lldbassert(false && "pointer size is not 4 nor 8");
654
}
655
StreamString idx_name;
656
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
657
658
DataExtractor data(buffer_sp, m_order, m_ptr_size);
659
660
set_item.valobj_sp = CreateValueObjectFromData(
661
idx_name.GetString(), data, m_exe_ctx_ref,
662
m_backend.GetCompilerType().GetBasicTypeFromAST(
663
lldb::eBasicTypeObjCID));
664
}
665
666
return set_item.valobj_sp;
667
}
668
669
template <typename D32, typename D64>
670
lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<
671
D32, D64>::GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
672
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
673
m_data_32(nullptr), m_data_64(nullptr) {
674
if (valobj_sp)
675
Update();
676
}
677
678
template <typename D32, typename D64>
679
lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::
680
GenericNSSetMSyntheticFrontEnd::~GenericNSSetMSyntheticFrontEnd() {
681
delete m_data_32;
682
m_data_32 = nullptr;
683
delete m_data_64;
684
m_data_64 = nullptr;
685
}
686
687
template <typename D32, typename D64>
688
size_t
689
lldb_private::formatters::
690
GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName(
691
ConstString name) {
692
const char *item_name = name.GetCString();
693
uint32_t idx = ExtractIndexFromString(item_name);
694
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
695
return UINT32_MAX;
696
return idx;
697
}
698
699
template <typename D32, typename D64>
700
llvm::Expected<uint32_t>
701
lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<
702
D32, D64>::CalculateNumChildren() {
703
if (!m_data_32 && !m_data_64)
704
return 0;
705
return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);
706
}
707
708
template <typename D32, typename D64>
709
lldb::ChildCacheState
710
lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {
711
m_children.clear();
712
ValueObjectSP valobj_sp = m_backend.GetSP();
713
m_ptr_size = 0;
714
delete m_data_32;
715
m_data_32 = nullptr;
716
delete m_data_64;
717
m_data_64 = nullptr;
718
if (!valobj_sp)
719
return lldb::ChildCacheState::eRefetch;
720
if (!valobj_sp)
721
return lldb::ChildCacheState::eRefetch;
722
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
723
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
724
if (!process_sp)
725
return lldb::ChildCacheState::eRefetch;
726
m_ptr_size = process_sp->GetAddressByteSize();
727
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
728
Status error;
729
if (m_ptr_size == 4) {
730
m_data_32 = new D32();
731
process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
732
error);
733
} else {
734
m_data_64 = new D64();
735
process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
736
error);
737
}
738
return error.Success() ? lldb::ChildCacheState::eReuse
739
: lldb::ChildCacheState::eRefetch;
740
}
741
742
template <typename D32, typename D64>
743
bool
744
lldb_private::formatters::
745
GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() {
746
return true;
747
}
748
749
template <typename D32, typename D64>
750
lldb::ValueObjectSP
751
lldb_private::formatters::
752
GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(uint32_t idx) {
753
lldb::addr_t m_objs_addr =
754
(m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
755
756
uint32_t num_children = CalculateNumChildrenIgnoringErrors();
757
758
if (idx >= num_children)
759
return lldb::ValueObjectSP();
760
761
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
762
if (!process_sp)
763
return lldb::ValueObjectSP();
764
765
if (m_children.empty()) {
766
// do the scan phase
767
lldb::addr_t obj_at_idx = 0;
768
769
uint32_t tries = 0;
770
uint32_t test_idx = 0;
771
772
while (tries < num_children) {
773
obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
774
if (!process_sp)
775
return lldb::ValueObjectSP();
776
Status error;
777
obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
778
if (error.Fail())
779
return lldb::ValueObjectSP();
780
781
test_idx++;
782
783
if (!obj_at_idx)
784
continue;
785
tries++;
786
787
SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
788
789
m_children.push_back(descriptor);
790
}
791
}
792
793
if (idx >= m_children.size()) // should never happen
794
return lldb::ValueObjectSP();
795
796
SetItemDescriptor &set_item = m_children[idx];
797
if (!set_item.valobj_sp) {
798
auto ptr_size = process_sp->GetAddressByteSize();
799
DataBufferHeap buffer(ptr_size, 0);
800
switch (ptr_size) {
801
case 0: // architecture has no clue?? - fail
802
return lldb::ValueObjectSP();
803
case 4:
804
*((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
805
break;
806
case 8:
807
*((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
808
break;
809
default:
810
assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
811
}
812
StreamString idx_name;
813
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
814
815
DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
816
process_sp->GetByteOrder(),
817
process_sp->GetAddressByteSize());
818
819
set_item.valobj_sp = CreateValueObjectFromData(
820
idx_name.GetString(), data, m_exe_ctx_ref,
821
m_backend.GetCompilerType().GetBasicTypeFromAST(
822
lldb::eBasicTypeObjCID));
823
}
824
return set_item.valobj_sp;
825
}
826
827
template bool lldb_private::formatters::NSSetSummaryProvider<true>(
828
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
829
830
template bool lldb_private::formatters::NSSetSummaryProvider<false>(
831
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
832
833