blob: 363bd5c0527e163ccd8973f31d281c39663b0993 [file] [log] [blame]
Enrico Granata5510a572014-10-15 21:38:32 +00001//===-- NSIndexPath.cpp ------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/DataFormatters/CXXFormatterFunctions.h"
11
12#include "lldb/Core/ValueObject.h"
13#include "lldb/Core/ValueObjectConstResult.h"
14#include "lldb/DataFormatters/TypeSynthetic.h"
15#include "lldb/Target/ObjCLanguageRuntime.h"
16#include "lldb/Target/Process.h"
17#include "lldb/Symbol/ClangASTContext.h"
18
19using namespace lldb;
20using namespace lldb_private;
21using namespace lldb_private::formatters;
22
23class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd
24{
25public:
26 NSIndexPathSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
27 SyntheticChildrenFrontEnd (*valobj_sp.get()),
28 m_ptr_size(0),
29 m_ast_ctx(nullptr),
30 m_uint_star_type()
31 {
32 m_ptr_size = m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
33 }
34
35 virtual size_t
36 CalculateNumChildren ()
37 {
38 return m_impl.GetNumIndexes();
39 }
40
41 virtual lldb::ValueObjectSP
42 GetChildAtIndex (size_t idx)
43 {
44 return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
45 }
46
47 virtual bool
48 Update()
49 {
Enrico Granata7569f232015-06-16 20:48:49 +000050 m_impl.Clear();
Enrico Granata5510a572014-10-15 21:38:32 +000051
Pavel Labathc7c30eb2015-06-08 23:38:06 +000052 m_ast_ctx = ClangASTContext::GetASTContext(m_backend.GetClangType().GetASTContext());
Enrico Granata5510a572014-10-15 21:38:32 +000053 if (!m_ast_ctx)
54 return false;
55
56 m_uint_star_type = m_ast_ctx->GetPointerSizedIntType(false);
57
58 static ConstString g__indexes("_indexes");
59 static ConstString g__length("_length");
60
61 ProcessSP process_sp = m_backend.GetProcessSP();
62 if (!process_sp)
63 return false;
64
65 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
66
67 if (!runtime)
68 return false;
69
70 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(m_backend));
71
72 if (!descriptor.get() || !descriptor->IsValid())
73 return false;
74
75 uint64_t info_bits(0),value_bits(0),payload(0);
76
77 if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload))
78 {
Enrico Granata5510a572014-10-15 21:38:32 +000079 m_impl.m_inlined.SetIndexes(payload, *process_sp);
Enrico Granata7569f232015-06-16 20:48:49 +000080 m_impl.m_mode = Mode::Inlined;
Enrico Granata5510a572014-10-15 21:38:32 +000081 }
82 else
83 {
84 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
85 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
86
87 bool has_indexes(false),has_length(false);
88
Zachary Turner225cc302015-01-09 20:15:03 +000089 for (size_t x = 0;
Enrico Granata5510a572014-10-15 21:38:32 +000090 x < descriptor->GetNumIVars();
91 x++)
92 {
93 const auto& ivar = descriptor->GetIVarAtIndex(x);
94 if (ivar.m_name == g__indexes)
95 {
96 _indexes_id = ivar;
97 has_indexes = true;
98 }
99 else if (ivar.m_name == g__length)
100 {
101 _length_id = ivar;
102 has_length = true;
103 }
104
105 if (has_length && has_indexes)
106 break;
107 }
108
109 if (has_length && has_indexes)
110 {
111 m_impl.m_outsourced.m_indexes = m_backend.GetSyntheticChildAtOffset(_indexes_id.m_offset,
112 m_uint_star_type.GetPointerType(),
113 true).get();
114 ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(_length_id.m_offset,
115 m_uint_star_type,
116 true));
117 if (length_sp)
118 {
119 m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
120 if (m_impl.m_outsourced.m_indexes)
121 m_impl.m_mode = Mode::Outsourced;
122 }
123 }
124 }
125 return false;
126 }
127
128 virtual bool
129 MightHaveChildren ()
130 {
131 if (m_impl.m_mode == Mode::Invalid)
132 return false;
133 return true;
134 }
135
136 virtual size_t
137 GetIndexOfChildWithName (const ConstString &name)
138 {
139 const char* item_name = name.GetCString();
140 uint32_t idx = ExtractIndexFromString(item_name);
141 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
142 return UINT32_MAX;
143 return idx;
144 }
145
146 virtual lldb::ValueObjectSP
147 GetSyntheticValue () { return nullptr; }
148
149 virtual
150 ~NSIndexPathSyntheticFrontEnd () {}
151
152protected:
153 ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
154
155 enum class Mode {
156 Inlined,
157 Outsourced,
158 Invalid
159 };
160
161 struct Impl {
162 Mode m_mode;
163
164 size_t
165 GetNumIndexes ()
166 {
167 switch (m_mode)
168 {
169 case Mode::Inlined:
170 return m_inlined.GetNumIndexes();
171 case Mode::Outsourced:
172 return m_outsourced.m_count;
173 default:
174 return 0;
175 }
176 }
177
178 lldb::ValueObjectSP
179 GetIndexAtIndex (size_t idx, const ClangASTType& desired_type)
180 {
181 if (idx >= GetNumIndexes())
182 return nullptr;
183 switch (m_mode)
184 {
185 default: return nullptr;
186 case Mode::Inlined:
187 return m_inlined.GetIndexAtIndex (idx, desired_type);
188 case Mode::Outsourced:
189 return m_outsourced.GetIndexAtIndex (idx);
190 }
191 }
Enrico Granata5510a572014-10-15 21:38:32 +0000192
Eric Christopher098f8982014-10-21 20:39:34 +0000193 struct InlinedIndexes {
Enrico Granata7569f232015-06-16 20:48:49 +0000194 public:
195 void SetIndexes(uint64_t value, Process& p)
196 {
197 m_indexes = value;
198 _lengthForInlinePayload(p.GetAddressByteSize());
199 m_process = &p;
200 }
201
202 size_t
203 GetNumIndexes ()
204 {
205 return m_count;
206 }
Eric Christopher098f8982014-10-21 20:39:34 +0000207
Enrico Granata7569f232015-06-16 20:48:49 +0000208 lldb::ValueObjectSP
209 GetIndexAtIndex (size_t idx, const ClangASTType& desired_type)
210 {
211 std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
212 if (!value.second)
213 return nullptr;
214
215 Value v;
216 if (m_ptr_size == 8)
217 {
218 Scalar scalar( (unsigned long long)value.first );
219 v = Value(scalar);
220 }
221 else
222 {
223 Scalar scalar( (unsigned int)value.first );
224 v = Value(scalar);
225 }
226
227 v.SetClangType(desired_type);
228
229 StreamString idx_name;
230 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
231
232 return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData()));
233 }
234
235 void
236 Clear ()
237 {
238 m_indexes = 0;
239 m_count = 0;
240 m_ptr_size = 0;
241 m_process = nullptr;
242 }
243
244 private:
245 uint64_t m_indexes;
246 size_t m_count;
247 uint32_t m_ptr_size;
248 Process *m_process;
249
250 // cfr. Foundation for the details of this code
251 size_t _lengthForInlinePayload(uint32_t ptr_size) {
252 m_ptr_size = ptr_size;
253 if (m_ptr_size == 8)
254 m_count = ((m_indexes >> 3) & 0x7);
255 else
256 m_count = ((m_indexes >> 3) & 0x3);
257 return m_count;
258 }
259
260 std::pair<uint64_t, bool>
261 _indexAtPositionForInlinePayload(size_t pos)
262 {
263 if (m_ptr_size == 8)
264 {
265 switch (pos) {
266 case 5: return {((m_indexes >> 51) & 0x1ff),true};
267 case 4: return {((m_indexes >> 42) & 0x1ff),true};
268 case 3: return {((m_indexes >> 33) & 0x1ff),true};
269 case 2: return {((m_indexes >> 24) & 0x1ff),true};
270 case 1: return {((m_indexes >> 15) & 0x1ff),true};
271 case 0: return {((m_indexes >> 6) & 0x1ff),true};
272 }
273 }
274 else
275 {
276 switch (pos) {
277 case 2: return {((m_indexes >> 23) & 0x1ff),true};
278 case 1: return {((m_indexes >> 14) & 0x1ff),true};
279 case 0: return {((m_indexes >> 5) & 0x1ff),true};
280 }
281 }
282 return {0,false};
283 }
284
285 };
Eric Christopher098f8982014-10-21 20:39:34 +0000286 struct OutsourcedIndexes {
Enrico Granata7569f232015-06-16 20:48:49 +0000287 ValueObject *m_indexes;
288 size_t m_count;
289
290 lldb::ValueObjectSP
291 GetIndexAtIndex (size_t idx)
292 {
293 if (m_indexes)
294 {
295 ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
296 return index_sp;
297 }
298 return nullptr;
299 }
300
301 void
302 Clear ()
303 {
304 m_indexes = nullptr;
305 m_count = 0;
306 }
307 };
Eric Christopher098f8982014-10-21 20:39:34 +0000308
309 union {
Enrico Granata7569f232015-06-16 20:48:49 +0000310 struct InlinedIndexes m_inlined;
311 struct OutsourcedIndexes m_outsourced;
Enrico Granata5510a572014-10-15 21:38:32 +0000312 };
Enrico Granata7569f232015-06-16 20:48:49 +0000313
314 void
315 Clear ()
316 {
317 m_mode = Mode::Invalid;
318 m_inlined.Clear();
319 m_outsourced.Clear();
320 }
Enrico Granata5510a572014-10-15 21:38:32 +0000321 } m_impl;
322
323 uint32_t m_ptr_size;
324 ClangASTContext* m_ast_ctx;
325 ClangASTType m_uint_star_type;
326};
327
328namespace lldb_private {
329 namespace formatters {
330
331 SyntheticChildrenFrontEnd* NSIndexPathSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
332 {
333 if (valobj_sp)
334 return new NSIndexPathSyntheticFrontEnd(valobj_sp);
335 return nullptr;
336 }
337 }
338}