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/NSIndexPath.cpp
39644 views
1
//===-- NSIndexPath.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 "Cocoa.h"
10
11
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12
#include "lldb/Core/ValueObject.h"
13
#include "lldb/Core/ValueObjectConstResult.h"
14
#include "lldb/DataFormatters/FormattersHelpers.h"
15
#include "lldb/DataFormatters/TypeSynthetic.h"
16
#include "lldb/Target/Process.h"
17
#include "lldb/Target/Target.h"
18
19
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
20
using namespace lldb;
21
using namespace lldb_private;
22
using namespace lldb_private::formatters;
23
24
static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
25
return (60 - (13 * (4 - i)));
26
}
27
28
static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {
29
return (32 - (13 * (2 - i)));
30
}
31
32
class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
33
public:
34
NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
35
: SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
36
m_impl(), m_uint_star_type() {
37
m_ptr_size =
38
m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
39
}
40
41
~NSIndexPathSyntheticFrontEnd() override = default;
42
43
llvm::Expected<uint32_t> CalculateNumChildren() override {
44
return m_impl.GetNumIndexes();
45
}
46
47
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
48
return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
49
}
50
51
lldb::ChildCacheState Update() override {
52
m_impl.Clear();
53
54
auto type_system = m_backend.GetCompilerType().GetTypeSystem();
55
if (!type_system)
56
return lldb::ChildCacheState::eRefetch;
57
58
auto ast = ScratchTypeSystemClang::GetForTarget(
59
*m_backend.GetExecutionContextRef().GetTargetSP());
60
if (!ast)
61
return lldb::ChildCacheState::eRefetch;
62
63
m_uint_star_type = ast->GetPointerSizedIntType(false);
64
65
static ConstString g__indexes("_indexes");
66
static ConstString g__length("_length");
67
68
ProcessSP process_sp = m_backend.GetProcessSP();
69
if (!process_sp)
70
return lldb::ChildCacheState::eRefetch;
71
72
ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
73
74
if (!runtime)
75
return lldb::ChildCacheState::eRefetch;
76
77
ObjCLanguageRuntime::ClassDescriptorSP descriptor(
78
runtime->GetClassDescriptor(m_backend));
79
80
if (!descriptor.get() || !descriptor->IsValid())
81
return lldb::ChildCacheState::eRefetch;
82
83
uint64_t info_bits(0), value_bits(0), payload(0);
84
85
if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {
86
m_impl.m_inlined.SetIndexes(payload, *process_sp);
87
m_impl.m_mode = Mode::Inlined;
88
} else {
89
ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
90
ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
91
92
bool has_indexes(false), has_length(false);
93
94
for (size_t x = 0; x < descriptor->GetNumIVars(); x++) {
95
const auto &ivar = descriptor->GetIVarAtIndex(x);
96
if (ivar.m_name == g__indexes) {
97
_indexes_id = ivar;
98
has_indexes = true;
99
} else if (ivar.m_name == g__length) {
100
_length_id = ivar;
101
has_length = true;
102
}
103
104
if (has_length && has_indexes)
105
break;
106
}
107
108
if (has_length && has_indexes) {
109
m_impl.m_outsourced.m_indexes =
110
m_backend
111
.GetSyntheticChildAtOffset(_indexes_id.m_offset,
112
m_uint_star_type.GetPointerType(),
113
true)
114
.get();
115
ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(
116
_length_id.m_offset, m_uint_star_type, true));
117
if (length_sp) {
118
m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
119
if (m_impl.m_outsourced.m_indexes)
120
m_impl.m_mode = Mode::Outsourced;
121
}
122
}
123
}
124
return lldb::ChildCacheState::eRefetch;
125
}
126
127
bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; }
128
129
size_t GetIndexOfChildWithName(ConstString name) override {
130
const char *item_name = name.GetCString();
131
uint32_t idx = ExtractIndexFromString(item_name);
132
if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
133
return UINT32_MAX;
134
return idx;
135
}
136
137
lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
138
139
protected:
140
ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
141
142
enum class Mode { Inlined, Outsourced, Invalid };
143
144
struct Impl {
145
size_t GetNumIndexes() {
146
switch (m_mode) {
147
case Mode::Inlined:
148
return m_inlined.GetNumIndexes();
149
case Mode::Outsourced:
150
return m_outsourced.m_count;
151
default:
152
return 0;
153
}
154
}
155
156
lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
157
const CompilerType &desired_type) {
158
if (idx >= GetNumIndexes())
159
return nullptr;
160
switch (m_mode) {
161
default:
162
return nullptr;
163
case Mode::Inlined:
164
return m_inlined.GetIndexAtIndex(idx, desired_type);
165
case Mode::Outsourced:
166
return m_outsourced.GetIndexAtIndex(idx);
167
}
168
}
169
170
struct InlinedIndexes {
171
public:
172
void SetIndexes(uint64_t value, Process &p) {
173
m_indexes = value;
174
_lengthForInlinePayload(p.GetAddressByteSize());
175
m_process = &p;
176
}
177
178
size_t GetNumIndexes() { return m_count; }
179
180
lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
181
const CompilerType &desired_type) {
182
if (!m_process)
183
return nullptr;
184
185
std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
186
if (!value.second)
187
return nullptr;
188
189
Value v;
190
if (m_ptr_size == 8) {
191
Scalar scalar((unsigned long long)value.first);
192
v = Value(scalar);
193
} else {
194
Scalar scalar((unsigned int)value.first);
195
v = Value(scalar);
196
}
197
198
v.SetCompilerType(desired_type);
199
200
StreamString idx_name;
201
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
202
203
return ValueObjectConstResult::Create(
204
m_process, v, ConstString(idx_name.GetString()));
205
}
206
207
void Clear() {
208
m_indexes = 0;
209
m_count = 0;
210
m_ptr_size = 0;
211
m_process = nullptr;
212
}
213
214
InlinedIndexes() {}
215
216
private:
217
uint64_t m_indexes = 0;
218
size_t m_count = 0;
219
uint32_t m_ptr_size = 0;
220
Process *m_process = nullptr;
221
222
// cfr. Foundation for the details of this code
223
size_t _lengthForInlinePayload(uint32_t ptr_size) {
224
m_ptr_size = ptr_size;
225
if (m_ptr_size == 8)
226
m_count = ((m_indexes >> 3) & 0x7);
227
else
228
m_count = ((m_indexes >> 3) & 0x3);
229
return m_count;
230
}
231
232
std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {
233
static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
234
if (m_ptr_size == 8) {
235
switch (pos) {
236
case 3:
237
case 2:
238
case 1:
239
case 0:
240
return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
241
PACKED_INDEX_MASK,
242
true};
243
default:
244
return {0, false};
245
}
246
} else {
247
switch (pos) {
248
case 0:
249
case 1:
250
return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
251
PACKED_INDEX_MASK,
252
true};
253
default:
254
return {0, false};
255
}
256
}
257
return {0, false};
258
}
259
};
260
261
struct OutsourcedIndexes {
262
lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {
263
if (m_indexes) {
264
ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
265
return index_sp;
266
}
267
return nullptr;
268
}
269
270
void Clear() {
271
m_indexes = nullptr;
272
m_count = 0;
273
}
274
275
OutsourcedIndexes() {}
276
277
ValueObject *m_indexes = nullptr;
278
size_t m_count = 0;
279
};
280
281
union {
282
struct InlinedIndexes m_inlined;
283
struct OutsourcedIndexes m_outsourced;
284
};
285
286
void Clear() {
287
switch (m_mode) {
288
case Mode::Inlined:
289
m_inlined.Clear();
290
break;
291
case Mode::Outsourced:
292
m_outsourced.Clear();
293
break;
294
case Mode::Invalid:
295
break;
296
}
297
m_mode = Mode::Invalid;
298
}
299
300
Impl() {}
301
302
Mode m_mode = Mode::Invalid;
303
} m_impl;
304
305
uint32_t m_ptr_size = 0;
306
CompilerType m_uint_star_type;
307
};
308
309
namespace lldb_private {
310
namespace formatters {
311
312
SyntheticChildrenFrontEnd *
313
NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,
314
lldb::ValueObjectSP valobj_sp) {
315
if (valobj_sp)
316
return new NSIndexPathSyntheticFrontEnd(valobj_sp);
317
return nullptr;
318
}
319
320
} // namespace formatters
321
} // namespace lldb_private
322
323