LLDB mainline
NSIndexPath.cpp
Go to the documentation of this file.
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
14#include "lldb/Target/Process.h"
15#include "lldb/Target/Target.h"
18
20using namespace lldb;
21using namespace lldb_private;
22using namespace lldb_private::formatters;
23
24static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
25 return (60 - (13 * (4 - i)));
26}
27
28static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {
29 return (32 - (13 * (2 - i)));
30}
31
33public:
35 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
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
52 m_impl.Clear();
53
54 auto type_system = m_backend.GetCompilerType().GetTypeSystem();
55 if (!type_system)
57
59 *m_backend.GetExecutionContextRef().GetTargetSP());
60 if (!ast)
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)
71
72 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
73
74 if (!runtime)
76
79
80 if (!descriptor.get() || !descriptor->IsValid())
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 {
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 =
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 }
125 }
126
127 bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; }
128
129 lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
130
131protected:
133
134 enum class Mode { Inlined, Outsourced, Invalid };
135
136 struct Impl {
137 size_t GetNumIndexes() {
138 switch (m_mode) {
139 case Mode::Inlined:
140 return m_inlined.GetNumIndexes();
141 case Mode::Outsourced:
142 return m_outsourced.m_count;
143 default:
144 return 0;
145 }
146 }
147
149 const CompilerType &desired_type) {
150 if (idx >= GetNumIndexes())
151 return nullptr;
152 switch (m_mode) {
153 default:
154 return nullptr;
155 case Mode::Inlined:
156 return m_inlined.GetIndexAtIndex(idx, desired_type);
157 case Mode::Outsourced:
158 return m_outsourced.GetIndexAtIndex(idx);
159 }
160 }
161
163 public:
164 void SetIndexes(uint64_t value, Process &p) {
165 m_indexes = value;
167 m_process = &p;
168 }
169
170 size_t GetNumIndexes() { return m_count; }
171
173 const CompilerType &desired_type) {
174 if (!m_process)
175 return nullptr;
176
177 std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
178 if (!value.second)
179 return nullptr;
180
181 Value v;
182 if (m_ptr_size == 8) {
183 Scalar scalar((unsigned long long)value.first);
184 v = Value(scalar);
185 } else {
186 Scalar scalar((unsigned int)value.first);
187 v = Value(scalar);
188 }
189
190 v.SetCompilerType(desired_type);
191
192 StreamString idx_name;
193 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
194
196 m_process, v, ConstString(idx_name.GetString()));
197 }
198
199 void Clear() {
200 m_indexes = 0;
201 m_count = 0;
202 m_ptr_size = 0;
203 m_process = nullptr;
204 }
205
207
208 private:
209 uint64_t m_indexes = 0;
210 size_t m_count = 0;
211 uint32_t m_ptr_size = 0;
212 Process *m_process = nullptr;
213
214 // cfr. Foundation for the details of this code
215 size_t _lengthForInlinePayload(uint32_t ptr_size) {
216 m_ptr_size = ptr_size;
217 if (m_ptr_size == 8)
218 m_count = ((m_indexes >> 3) & 0x7);
219 else
220 m_count = ((m_indexes >> 3) & 0x3);
221 return m_count;
222 }
223
224 std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {
225 static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
226 if (m_ptr_size == 8) {
227 switch (pos) {
228 case 3:
229 case 2:
230 case 1:
231 case 0:
232 return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
233 PACKED_INDEX_MASK,
234 true};
235 default:
236 return {0, false};
237 }
238 } else {
239 switch (pos) {
240 case 0:
241 case 1:
242 return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
243 PACKED_INDEX_MASK,
244 true};
245 default:
246 return {0, false};
247 }
248 }
249 return {0, false};
250 }
251 };
252
255 if (m_indexes) {
256 ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
257 return index_sp;
258 }
259 return nullptr;
260 }
261
262 void Clear() {
263 m_indexes = nullptr;
264 m_count = 0;
265 }
266
268
270 size_t m_count = 0;
271 };
272
273 union {
276 };
277
278 void Clear() {
279 switch (m_mode) {
280 case Mode::Inlined:
281 m_inlined.Clear();
282 break;
283 case Mode::Outsourced:
284 m_outsourced.Clear();
285 break;
286 case Mode::Invalid:
287 break;
288 }
290 }
291
292 Impl() {}
293
296
297 uint32_t m_ptr_size = 0;
299};
300
301namespace lldb_private {
302namespace formatters {
303
306 lldb::ValueObjectSP valobj_sp) {
307 if (valobj_sp)
308 return new NSIndexPathSyntheticFrontEnd(valobj_sp);
309 return nullptr;
310}
311
312} // namespace formatters
313} // namespace lldb_private
static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i)
static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i)
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
llvm::Expected< uint32_t > CalculateNumChildren() override
struct NSIndexPathSyntheticFrontEnd::Impl m_impl
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
~NSIndexPathSyntheticFrontEnd() override=default
NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp
bool MightHaveChildren() override
lldb::ValueObjectSP GetSyntheticValue() override
Generic representation of a type in a programming language.
A uniqued constant string class.
Definition ConstString.h:40
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
static ObjCLanguageRuntime * Get(Process &process)
virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value)
A plug-in interface definition class for debugging a process.
Definition Process.h:354
uint32_t GetAddressByteSize() const
Definition Process.cpp:3725
static lldb::TypeSystemClangSP GetForTarget(Target &target, std::optional< IsolatedASTKind > ast_kind=DefaultAST, bool create_on_demand=true)
Returns the scratch TypeSystemClang for the given target.
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
SyntheticChildrenFrontEnd(ValueObject &backend)
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size, lldb::addr_t address=LLDB_INVALID_ADDRESS)
void SetCompilerType(const CompilerType &compiler_type)
Definition Value.cpp:276
SyntheticChildrenFrontEnd * NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
A class that represents a running process on the host machine.
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::Process > ProcessSP
void SetIndexes(uint64_t value, Process &p)
lldb::ValueObjectSP GetIndexAtIndex(size_t idx, const CompilerType &desired_type)
std::pair< uint64_t, bool > _indexAtPositionForInlinePayload(size_t pos)
lldb::ValueObjectSP GetIndexAtIndex(size_t idx, const CompilerType &desired_type)
struct OutsourcedIndexes m_outsourced