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/NSArray.cpp
39644 views
1
//===-- NSArray.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 "clang/AST/ASTContext.h"
10
#include "clang/Basic/TargetInfo.h"
11
12
#include "Cocoa.h"
13
14
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
15
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
16
17
#include "lldb/Core/ValueObject.h"
18
#include "lldb/Core/ValueObjectConstResult.h"
19
#include "lldb/DataFormatters/FormattersHelpers.h"
20
#include "lldb/Expression/FunctionCaller.h"
21
#include "lldb/Target/Language.h"
22
#include "lldb/Target/Target.h"
23
#include "lldb/Utility/DataBufferHeap.h"
24
#include "lldb/Utility/Endian.h"
25
#include "lldb/Utility/Status.h"
26
#include "lldb/Utility/Stream.h"
27
28
using namespace lldb;
29
using namespace lldb_private;
30
using namespace lldb_private::formatters;
31
32
namespace lldb_private {
33
namespace formatters {
34
std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
35
NSArray_Additionals::GetAdditionalSummaries() {
36
static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
37
return g_map;
38
}
39
40
std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
41
NSArray_Additionals::GetAdditionalSynthetics() {
42
static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
43
g_map;
44
return g_map;
45
}
46
47
class NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd {
48
public:
49
NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp);
50
51
~NSArrayMSyntheticFrontEndBase() override = default;
52
53
llvm::Expected<uint32_t> CalculateNumChildren() override;
54
55
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
56
57
lldb::ChildCacheState Update() override = 0;
58
59
bool MightHaveChildren() override;
60
61
size_t GetIndexOfChildWithName(ConstString name) override;
62
63
protected:
64
virtual lldb::addr_t GetDataAddress() = 0;
65
66
virtual uint64_t GetUsedCount() = 0;
67
68
virtual uint64_t GetOffset() = 0;
69
70
virtual uint64_t GetSize() = 0;
71
72
ExecutionContextRef m_exe_ctx_ref;
73
uint8_t m_ptr_size = 8;
74
CompilerType m_id_type;
75
};
76
77
template <typename D32, typename D64>
78
class GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase {
79
public:
80
GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
81
82
~GenericNSArrayMSyntheticFrontEnd() override;
83
84
lldb::ChildCacheState Update() override;
85
86
protected:
87
lldb::addr_t GetDataAddress() override;
88
89
uint64_t GetUsedCount() override;
90
91
uint64_t GetOffset() override;
92
93
uint64_t GetSize() override;
94
95
private:
96
D32 *m_data_32;
97
D64 *m_data_64;
98
};
99
100
namespace Foundation1010 {
101
namespace {
102
struct DataDescriptor_32 {
103
uint32_t _used;
104
uint32_t _offset;
105
uint32_t _size : 28;
106
uint64_t _priv1 : 4;
107
uint32_t _priv2;
108
uint32_t _data;
109
};
110
111
struct DataDescriptor_64 {
112
uint64_t _used;
113
uint64_t _offset;
114
uint64_t _size : 60;
115
uint64_t _priv1 : 4;
116
uint32_t _priv2;
117
uint64_t _data;
118
};
119
}
120
121
using NSArrayMSyntheticFrontEnd =
122
GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
123
}
124
125
namespace Foundation1428 {
126
namespace {
127
struct DataDescriptor_32 {
128
uint32_t _used;
129
uint32_t _offset;
130
uint32_t _size;
131
uint32_t _data;
132
};
133
134
struct DataDescriptor_64 {
135
uint64_t _used;
136
uint64_t _offset;
137
uint64_t _size;
138
uint64_t _data;
139
};
140
}
141
142
using NSArrayMSyntheticFrontEnd =
143
GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
144
}
145
146
namespace Foundation1437 {
147
template <typename PtrType>
148
struct DataDescriptor {
149
PtrType _cow;
150
// __deque
151
PtrType _data;
152
uint32_t _offset;
153
uint32_t _size;
154
uint32_t _muts;
155
uint32_t _used;
156
};
157
158
using NSArrayMSyntheticFrontEnd =
159
GenericNSArrayMSyntheticFrontEnd<
160
DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>;
161
162
template <typename DD>
163
uint64_t
164
__NSArrayMSize_Impl(lldb_private::Process &process,
165
lldb::addr_t valobj_addr, Status &error) {
166
const lldb::addr_t start_of_descriptor =
167
valobj_addr + process.GetAddressByteSize();
168
DD descriptor = DD();
169
process.ReadMemory(start_of_descriptor, &descriptor,
170
sizeof(descriptor), error);
171
if (error.Fail()) {
172
return 0;
173
}
174
return descriptor._used;
175
}
176
177
uint64_t
178
__NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
179
Status &error) {
180
if (process.GetAddressByteSize() == 4) {
181
return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr,
182
error);
183
} else {
184
return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr,
185
error);
186
}
187
}
188
189
}
190
191
namespace CallStackArray {
192
struct DataDescriptor_32 {
193
uint32_t _data;
194
uint32_t _used;
195
uint32_t _offset;
196
const uint32_t _size = 0;
197
};
198
199
struct DataDescriptor_64 {
200
uint64_t _data;
201
uint64_t _used;
202
uint64_t _offset;
203
const uint64_t _size = 0;
204
};
205
206
using NSCallStackArraySyntheticFrontEnd =
207
GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
208
} // namespace CallStackArray
209
210
template <typename D32, typename D64, bool Inline>
211
class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
212
public:
213
GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
214
215
~GenericNSArrayISyntheticFrontEnd() override;
216
217
llvm::Expected<uint32_t> CalculateNumChildren() override;
218
219
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
220
221
lldb::ChildCacheState Update() override;
222
223
bool MightHaveChildren() override;
224
225
size_t GetIndexOfChildWithName(ConstString name) override;
226
227
private:
228
ExecutionContextRef m_exe_ctx_ref;
229
uint8_t m_ptr_size = 8;
230
231
D32 *m_data_32;
232
D64 *m_data_64;
233
CompilerType m_id_type;
234
};
235
236
namespace Foundation1300 {
237
struct IDD32 {
238
uint32_t used;
239
uint32_t list;
240
};
241
242
struct IDD64 {
243
uint64_t used;
244
uint64_t list;
245
};
246
247
using NSArrayISyntheticFrontEnd =
248
GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
249
}
250
251
namespace Foundation1430 {
252
using NSArrayISyntheticFrontEnd =
253
Foundation1428::NSArrayMSyntheticFrontEnd;
254
}
255
256
namespace Foundation1436 {
257
struct IDD32 {
258
uint32_t used;
259
uint32_t list; // in Inline cases, this is the first element
260
};
261
262
struct IDD64 {
263
uint64_t used;
264
uint64_t list; // in Inline cases, this is the first element
265
};
266
267
using NSArrayI_TransferSyntheticFrontEnd =
268
GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>;
269
270
using NSArrayISyntheticFrontEnd =
271
GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
272
273
using NSFrozenArrayMSyntheticFrontEnd =
274
Foundation1437::NSArrayMSyntheticFrontEnd;
275
276
uint64_t
277
__NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
278
Status &error) {
279
return Foundation1437::__NSArrayMSize(process, valobj_addr, error);
280
}
281
}
282
283
namespace ConstantArray {
284
285
struct ConstantArray32 {
286
uint64_t used;
287
uint32_t list;
288
};
289
290
struct ConstantArray64 {
291
uint64_t used;
292
uint64_t list;
293
};
294
295
using NSConstantArraySyntheticFrontEnd =
296
GenericNSArrayISyntheticFrontEnd<ConstantArray32, ConstantArray64, false>;
297
} // namespace ConstantArray
298
299
class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
300
public:
301
NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
302
303
~NSArray0SyntheticFrontEnd() override = default;
304
305
llvm::Expected<uint32_t> CalculateNumChildren() override;
306
307
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
308
309
lldb::ChildCacheState Update() override;
310
311
bool MightHaveChildren() override;
312
313
size_t GetIndexOfChildWithName(ConstString name) override;
314
};
315
316
class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
317
public:
318
NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
319
320
~NSArray1SyntheticFrontEnd() override = default;
321
322
llvm::Expected<uint32_t> CalculateNumChildren() override;
323
324
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
325
326
lldb::ChildCacheState Update() override;
327
328
bool MightHaveChildren() override;
329
330
size_t GetIndexOfChildWithName(ConstString name) override;
331
};
332
} // namespace formatters
333
} // namespace lldb_private
334
335
bool lldb_private::formatters::NSArraySummaryProvider(
336
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
337
static constexpr llvm::StringLiteral g_TypeHint("NSArray");
338
339
ProcessSP process_sp = valobj.GetProcessSP();
340
if (!process_sp)
341
return false;
342
343
ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
344
345
if (!runtime)
346
return false;
347
348
ObjCLanguageRuntime::ClassDescriptorSP descriptor(
349
runtime->GetClassDescriptor(valobj));
350
351
if (!descriptor || !descriptor->IsValid())
352
return false;
353
354
uint32_t ptr_size = process_sp->GetAddressByteSize();
355
356
lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
357
358
if (!valobj_addr)
359
return false;
360
361
uint64_t value = 0;
362
363
ConstString class_name(descriptor->GetClassName());
364
365
static const ConstString g_NSArrayI("__NSArrayI");
366
static const ConstString g_NSArrayM("__NSArrayM");
367
static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
368
static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
369
static const ConstString g_NSArray0("__NSArray0");
370
static const ConstString g_NSArray1("__NSSingleObjectArrayI");
371
static const ConstString g_NSArrayCF("__NSCFArray");
372
static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
373
static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
374
static const ConstString g_NSCallStackArray("_NSCallStackArray");
375
static const ConstString g_NSConstantArray("NSConstantArray");
376
377
if (class_name.IsEmpty())
378
return false;
379
380
if (class_name == g_NSArrayI) {
381
Status error;
382
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
383
ptr_size, 0, error);
384
if (error.Fail())
385
return false;
386
} else if (class_name == g_NSConstantArray) {
387
Status error;
388
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 8,
389
0, error);
390
if (error.Fail())
391
return false;
392
} else if (class_name == g_NSArrayM) {
393
AppleObjCRuntime *apple_runtime =
394
llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
395
Status error;
396
if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
397
value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error);
398
} else {
399
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
400
ptr_size, 0, error);
401
}
402
if (error.Fail())
403
return false;
404
} else if (class_name == g_NSArrayI_Transfer) {
405
Status error;
406
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
407
ptr_size, 0, error);
408
if (error.Fail())
409
return false;
410
} else if (class_name == g_NSFrozenArrayM) {
411
Status error;
412
value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error);
413
if (error.Fail())
414
return false;
415
} else if (class_name == g_NSArrayMLegacy) {
416
Status error;
417
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
418
ptr_size, 0, error);
419
if (error.Fail())
420
return false;
421
} else if (class_name == g_NSArrayMImmutable) {
422
Status error;
423
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
424
ptr_size, 0, error);
425
if (error.Fail())
426
return false;
427
} else if (class_name == g_NSArray0) {
428
value = 0;
429
} else if (class_name == g_NSArray1) {
430
value = 1;
431
} else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) {
432
// __NSCFArray and _NSCallStackArray store the number of elements as a
433
// pointer-sized value at offset `2 * ptr_size`.
434
Status error;
435
value = process_sp->ReadUnsignedIntegerFromMemory(
436
valobj_addr + 2 * ptr_size, ptr_size, 0, error);
437
if (error.Fail())
438
return false;
439
} else {
440
auto &map(NSArray_Additionals::GetAdditionalSummaries());
441
auto iter = map.find(class_name), end = map.end();
442
if (iter != end)
443
return iter->second(valobj, stream, options);
444
else
445
return false;
446
}
447
448
llvm::StringRef prefix, suffix;
449
if (Language *language = Language::FindPlugin(options.GetLanguage()))
450
std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
451
452
stream << prefix;
453
stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");
454
stream << suffix;
455
return true;
456
}
457
458
lldb_private::formatters::NSArrayMSyntheticFrontEndBase::
459
NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp)
460
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_id_type() {
461
if (valobj_sp) {
462
TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(
463
*valobj_sp->GetExecutionContextRef().GetTargetSP());
464
if (scratch_ts_sp)
465
m_id_type = CompilerType(
466
scratch_ts_sp->weak_from_this(),
467
scratch_ts_sp->getASTContext().ObjCBuiltinIdTy.getAsOpaquePtr());
468
if (valobj_sp->GetProcessSP())
469
m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
470
}
471
}
472
473
template <typename D32, typename D64>
474
lldb_private::formatters::
475
GenericNSArrayMSyntheticFrontEnd<D32, D64>::
476
GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
477
: NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr),
478
m_data_64(nullptr) {}
479
480
llvm::Expected<uint32_t> lldb_private::formatters::
481
NSArrayMSyntheticFrontEndBase::CalculateNumChildren() {
482
return GetUsedCount();
483
}
484
485
lldb::ValueObjectSP
486
lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(
487
uint32_t idx) {
488
if (idx >= CalculateNumChildrenIgnoringErrors())
489
return lldb::ValueObjectSP();
490
lldb::addr_t object_at_idx = GetDataAddress();
491
size_t pyhs_idx = idx;
492
pyhs_idx += GetOffset();
493
if (GetSize() <= pyhs_idx)
494
pyhs_idx -= GetSize();
495
object_at_idx += (pyhs_idx * m_ptr_size);
496
StreamString idx_name;
497
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
498
return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
499
m_exe_ctx_ref, m_id_type);
500
}
501
502
template <typename D32, typename D64>
503
lldb::ChildCacheState
504
lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {
505
ValueObjectSP valobj_sp = m_backend.GetSP();
506
m_ptr_size = 0;
507
delete m_data_32;
508
m_data_32 = nullptr;
509
delete m_data_64;
510
m_data_64 = nullptr;
511
if (!valobj_sp)
512
return lldb::ChildCacheState::eRefetch;
513
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
514
Status error;
515
error.Clear();
516
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
517
if (!process_sp)
518
return lldb::ChildCacheState::eRefetch;
519
m_ptr_size = process_sp->GetAddressByteSize();
520
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
521
if (m_ptr_size == 4) {
522
m_data_32 = new D32();
523
process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
524
error);
525
} else {
526
m_data_64 = new D64();
527
process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
528
error);
529
}
530
531
return error.Success() ? lldb::ChildCacheState::eReuse
532
: lldb::ChildCacheState::eRefetch;
533
}
534
535
bool
536
lldb_private::formatters::NSArrayMSyntheticFrontEndBase::MightHaveChildren() {
537
return true;
538
}
539
540
size_t
541
lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName(
542
ConstString name) {
543
const char *item_name = name.GetCString();
544
uint32_t idx = ExtractIndexFromString(item_name);
545
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
546
return UINT32_MAX;
547
return idx;
548
}
549
550
template <typename D32, typename D64>
551
lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::
552
GenericNSArrayMSyntheticFrontEnd::~GenericNSArrayMSyntheticFrontEnd() {
553
delete m_data_32;
554
m_data_32 = nullptr;
555
delete m_data_64;
556
m_data_64 = nullptr;
557
}
558
559
template <typename D32, typename D64>
560
lldb::addr_t
561
lldb_private::formatters::
562
GenericNSArrayMSyntheticFrontEnd<D32, D64>::
563
GenericNSArrayMSyntheticFrontEnd::GetDataAddress() {
564
if (!m_data_32 && !m_data_64)
565
return LLDB_INVALID_ADDRESS;
566
return m_data_32 ? m_data_32->_data : m_data_64->_data;
567
}
568
569
template <typename D32, typename D64>
570
uint64_t
571
lldb_private::formatters::
572
GenericNSArrayMSyntheticFrontEnd<D32, D64>::
573
GenericNSArrayMSyntheticFrontEnd::GetUsedCount() {
574
if (!m_data_32 && !m_data_64)
575
return 0;
576
return m_data_32 ? m_data_32->_used : m_data_64->_used;
577
}
578
579
template <typename D32, typename D64>
580
uint64_t
581
lldb_private::formatters::
582
GenericNSArrayMSyntheticFrontEnd<D32, D64>::
583
GenericNSArrayMSyntheticFrontEnd::GetOffset() {
584
if (!m_data_32 && !m_data_64)
585
return 0;
586
return m_data_32 ? m_data_32->_offset : m_data_64->_offset;
587
}
588
589
template <typename D32, typename D64>
590
uint64_t
591
lldb_private::formatters::
592
GenericNSArrayMSyntheticFrontEnd<D32, D64>::
593
GenericNSArrayMSyntheticFrontEnd::GetSize() {
594
if (!m_data_32 && !m_data_64)
595
return 0;
596
return m_data_32 ? m_data_32->_size : m_data_64->_size;
597
}
598
599
template <typename D32, typename D64, bool Inline>
600
lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
601
GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
602
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
603
m_data_32(nullptr), m_data_64(nullptr) {
604
if (valobj_sp) {
605
CompilerType type = valobj_sp->GetCompilerType();
606
if (type) {
607
TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(
608
*valobj_sp->GetExecutionContextRef().GetTargetSP());
609
if (scratch_ts_sp)
610
m_id_type = scratch_ts_sp->GetType(
611
scratch_ts_sp->getASTContext().ObjCBuiltinIdTy);
612
}
613
}
614
}
615
616
template <typename D32, typename D64, bool Inline>
617
lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
618
GenericNSArrayISyntheticFrontEnd::~GenericNSArrayISyntheticFrontEnd() {
619
delete m_data_32;
620
m_data_32 = nullptr;
621
delete m_data_64;
622
m_data_64 = nullptr;
623
}
624
625
template <typename D32, typename D64, bool Inline>
626
size_t
627
lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
628
GetIndexOfChildWithName(ConstString name) {
629
const char *item_name = name.GetCString();
630
uint32_t idx = ExtractIndexFromString(item_name);
631
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
632
return UINT32_MAX;
633
return idx;
634
}
635
636
template <typename D32, typename D64, bool Inline>
637
llvm::Expected<uint32_t>
638
lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<
639
D32, D64, Inline>::CalculateNumChildren() {
640
return m_data_32 ? m_data_32->used : m_data_64->used;
641
}
642
643
template <typename D32, typename D64, bool Inline>
644
lldb::ChildCacheState
645
lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64,
646
Inline>::Update() {
647
ValueObjectSP valobj_sp = m_backend.GetSP();
648
m_ptr_size = 0;
649
delete m_data_32;
650
m_data_32 = nullptr;
651
delete m_data_64;
652
m_data_64 = nullptr;
653
if (!valobj_sp)
654
return lldb::ChildCacheState::eRefetch;
655
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
656
Status error;
657
error.Clear();
658
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
659
if (!process_sp)
660
return lldb::ChildCacheState::eRefetch;
661
m_ptr_size = process_sp->GetAddressByteSize();
662
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
663
if (m_ptr_size == 4) {
664
m_data_32 = new D32();
665
process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
666
error);
667
} else {
668
m_data_64 = new D64();
669
process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
670
error);
671
}
672
673
return error.Success() ? lldb::ChildCacheState::eReuse
674
: lldb::ChildCacheState::eRefetch;
675
}
676
677
template <typename D32, typename D64, bool Inline>
678
bool
679
lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
680
MightHaveChildren() {
681
return true;
682
}
683
684
template <typename D32, typename D64, bool Inline>
685
lldb::ValueObjectSP
686
lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
687
GetChildAtIndex(uint32_t idx) {
688
if (idx >= CalculateNumChildrenIgnoringErrors())
689
return lldb::ValueObjectSP();
690
lldb::addr_t object_at_idx;
691
if (Inline) {
692
object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size;
693
object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header
694
object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer
695
} else {
696
object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
697
}
698
object_at_idx += (idx * m_ptr_size);
699
700
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
701
if (!process_sp)
702
return lldb::ValueObjectSP();
703
Status error;
704
if (error.Fail())
705
return lldb::ValueObjectSP();
706
StreamString idx_name;
707
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
708
return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
709
m_exe_ctx_ref, m_id_type);
710
}
711
712
lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
713
lldb::ValueObjectSP valobj_sp)
714
: SyntheticChildrenFrontEnd(*valobj_sp) {}
715
716
size_t
717
lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(
718
ConstString name) {
719
return UINT32_MAX;
720
}
721
722
llvm::Expected<uint32_t>
723
lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {
724
return 0;
725
}
726
727
lldb::ChildCacheState
728
lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {
729
return lldb::ChildCacheState::eRefetch;
730
}
731
732
bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {
733
return false;
734
}
735
736
lldb::ValueObjectSP
737
lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(
738
uint32_t idx) {
739
return lldb::ValueObjectSP();
740
}
741
742
lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(
743
lldb::ValueObjectSP valobj_sp)
744
: SyntheticChildrenFrontEnd(*valobj_sp.get()) {}
745
746
size_t
747
lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(
748
ConstString name) {
749
static const ConstString g_zero("[0]");
750
751
if (name == g_zero)
752
return 0;
753
754
return UINT32_MAX;
755
}
756
757
llvm::Expected<uint32_t>
758
lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {
759
return 1;
760
}
761
762
lldb::ChildCacheState
763
lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {
764
return lldb::ChildCacheState::eRefetch;
765
}
766
767
bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() {
768
return true;
769
}
770
771
lldb::ValueObjectSP
772
lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(
773
uint32_t idx) {
774
static const ConstString g_zero("[0]");
775
776
if (idx == 0) {
777
TypeSystemClangSP scratch_ts_sp =
778
ScratchTypeSystemClang::GetForTarget(*m_backend.GetTargetSP());
779
if (scratch_ts_sp) {
780
CompilerType id_type(scratch_ts_sp->GetBasicType(lldb::eBasicTypeObjCID));
781
return m_backend.GetSyntheticChildAtOffset(
782
m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true,
783
g_zero);
784
}
785
}
786
return lldb::ValueObjectSP();
787
}
788
789
SyntheticChildrenFrontEnd *
790
lldb_private::formatters::NSArraySyntheticFrontEndCreator(
791
CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
792
if (!valobj_sp)
793
return nullptr;
794
795
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
796
if (!process_sp)
797
return nullptr;
798
AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
799
ObjCLanguageRuntime::Get(*process_sp));
800
if (!runtime)
801
return nullptr;
802
803
CompilerType valobj_type(valobj_sp->GetCompilerType());
804
Flags flags(valobj_type.GetTypeInfo());
805
806
if (flags.IsClear(eTypeIsPointer)) {
807
Status error;
808
valobj_sp = valobj_sp->AddressOf(error);
809
if (error.Fail() || !valobj_sp)
810
return nullptr;
811
}
812
813
ObjCLanguageRuntime::ClassDescriptorSP descriptor(
814
runtime->GetClassDescriptor(*valobj_sp));
815
816
if (!descriptor || !descriptor->IsValid())
817
return nullptr;
818
819
ConstString class_name(descriptor->GetClassName());
820
821
static const ConstString g_NSArrayI("__NSArrayI");
822
static const ConstString g_NSConstantArray("NSConstantArray");
823
static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
824
static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
825
static const ConstString g_NSArrayM("__NSArrayM");
826
static const ConstString g_NSArray0("__NSArray0");
827
static const ConstString g_NSArray1("__NSSingleObjectArrayI");
828
static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
829
static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
830
static const ConstString g_NSCallStackArray("_NSCallStackArray");
831
832
if (class_name.IsEmpty())
833
return nullptr;
834
835
if (class_name == g_NSArrayI) {
836
if (runtime->GetFoundationVersion() >= 1436)
837
return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp));
838
if (runtime->GetFoundationVersion() >= 1430)
839
return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp));
840
return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));
841
} else if (class_name == g_NSArrayI_Transfer) {
842
return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));
843
} else if (class_name == g_NSConstantArray) {
844
return new ConstantArray::NSConstantArraySyntheticFrontEnd(valobj_sp);
845
} else if (class_name == g_NSFrozenArrayM) {
846
return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));
847
} else if (class_name == g_NSArray0) {
848
return (new NSArray0SyntheticFrontEnd(valobj_sp));
849
} else if (class_name == g_NSArray1) {
850
return (new NSArray1SyntheticFrontEnd(valobj_sp));
851
} else if (class_name == g_NSArrayM) {
852
if (runtime->GetFoundationVersion() >= 1437)
853
return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp));
854
if (runtime->GetFoundationVersion() >= 1428)
855
return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp));
856
if (runtime->GetFoundationVersion() >= 1100)
857
return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));
858
} else if (class_name == g_NSCallStackArray) {
859
return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp));
860
} else {
861
auto &map(NSArray_Additionals::GetAdditionalSynthetics());
862
auto iter = map.find(class_name), end = map.end();
863
if (iter != end)
864
return iter->second(synth, valobj_sp);
865
}
866
867
return nullptr;
868
}
869
870