blob: 60768b1d15d66c05febc69e3cb38109af941c254 [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
Greg Claytond8d4a572015-08-11 21:38:15 +000052 TypeSystem* type_system = m_backend.GetClangType().GetTypeSystem();
53 if (!type_system)
54 return false;
55 m_ast_ctx = type_system->AsClangASTContext();
Enrico Granata5510a572014-10-15 21:38:32 +000056 if (!m_ast_ctx)
57 return false;
58
59 m_uint_star_type = m_ast_ctx->GetPointerSizedIntType(false);
60
61 static ConstString g__indexes("_indexes");
62 static ConstString g__length("_length");
63
64 ProcessSP process_sp = m_backend.GetProcessSP();
65 if (!process_sp)
66 return false;
67
68 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
69
70 if (!runtime)
71 return false;
72
73 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(m_backend));
74
75 if (!descriptor.get() || !descriptor->IsValid())
76 return false;
77
78 uint64_t info_bits(0),value_bits(0),payload(0);
79
80 if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload))
81 {
Enrico Granata5510a572014-10-15 21:38:32 +000082 m_impl.m_inlined.SetIndexes(payload, *process_sp);
Enrico Granata7569f232015-06-16 20:48:49 +000083 m_impl.m_mode = Mode::Inlined;
Enrico Granata5510a572014-10-15 21:38:32 +000084 }
85 else
86 {
87 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
88 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
89
90 bool has_indexes(false),has_length(false);
91
Zachary Turner225cc302015-01-09 20:15:03 +000092 for (size_t x = 0;
Enrico Granata5510a572014-10-15 21:38:32 +000093 x < descriptor->GetNumIVars();
94 x++)
95 {
96 const auto& ivar = descriptor->GetIVarAtIndex(x);
97 if (ivar.m_name == g__indexes)
98 {
99 _indexes_id = ivar;
100 has_indexes = true;
101 }
102 else if (ivar.m_name == g__length)
103 {
104 _length_id = ivar;
105 has_length = true;
106 }
107
108 if (has_length && has_indexes)
109 break;
110 }
111
112 if (has_length && has_indexes)
113 {
114 m_impl.m_outsourced.m_indexes = m_backend.GetSyntheticChildAtOffset(_indexes_id.m_offset,
115 m_uint_star_type.GetPointerType(),
116 true).get();
117 ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(_length_id.m_offset,
118 m_uint_star_type,
119 true));
120 if (length_sp)
121 {
122 m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
123 if (m_impl.m_outsourced.m_indexes)
124 m_impl.m_mode = Mode::Outsourced;
125 }
126 }
127 }
128 return false;
129 }
130
131 virtual bool
132 MightHaveChildren ()
133 {
134 if (m_impl.m_mode == Mode::Invalid)
135 return false;
136 return true;
137 }
138
139 virtual size_t
140 GetIndexOfChildWithName (const ConstString &name)
141 {
142 const char* item_name = name.GetCString();
143 uint32_t idx = ExtractIndexFromString(item_name);
144 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
145 return UINT32_MAX;
146 return idx;
147 }
148
149 virtual lldb::ValueObjectSP
150 GetSyntheticValue () { return nullptr; }
151
152 virtual
153 ~NSIndexPathSyntheticFrontEnd () {}
154
155protected:
156 ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
157
158 enum class Mode {
159 Inlined,
160 Outsourced,
161 Invalid
162 };
163
164 struct Impl {
165 Mode m_mode;
166
167 size_t
168 GetNumIndexes ()
169 {
170 switch (m_mode)
171 {
172 case Mode::Inlined:
173 return m_inlined.GetNumIndexes();
174 case Mode::Outsourced:
175 return m_outsourced.m_count;
176 default:
177 return 0;
178 }
179 }
180
181 lldb::ValueObjectSP
Greg Claytona1e5dc82015-08-11 22:53:00 +0000182 GetIndexAtIndex (size_t idx, const CompilerType& desired_type)
Enrico Granata5510a572014-10-15 21:38:32 +0000183 {
184 if (idx >= GetNumIndexes())
185 return nullptr;
186 switch (m_mode)
187 {
188 default: return nullptr;
189 case Mode::Inlined:
190 return m_inlined.GetIndexAtIndex (idx, desired_type);
191 case Mode::Outsourced:
192 return m_outsourced.GetIndexAtIndex (idx);
193 }
194 }
Enrico Granata5510a572014-10-15 21:38:32 +0000195
Eric Christopher098f8982014-10-21 20:39:34 +0000196 struct InlinedIndexes {
Enrico Granata7569f232015-06-16 20:48:49 +0000197 public:
198 void SetIndexes(uint64_t value, Process& p)
199 {
200 m_indexes = value;
201 _lengthForInlinePayload(p.GetAddressByteSize());
202 m_process = &p;
203 }
204
205 size_t
206 GetNumIndexes ()
207 {
208 return m_count;
209 }
Eric Christopher098f8982014-10-21 20:39:34 +0000210
Enrico Granata7569f232015-06-16 20:48:49 +0000211 lldb::ValueObjectSP
Greg Claytona1e5dc82015-08-11 22:53:00 +0000212 GetIndexAtIndex (size_t idx, const CompilerType& desired_type)
Enrico Granata7569f232015-06-16 20:48:49 +0000213 {
214 std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
215 if (!value.second)
216 return nullptr;
217
218 Value v;
219 if (m_ptr_size == 8)
220 {
221 Scalar scalar( (unsigned long long)value.first );
222 v = Value(scalar);
223 }
224 else
225 {
226 Scalar scalar( (unsigned int)value.first );
227 v = Value(scalar);
228 }
229
230 v.SetClangType(desired_type);
231
232 StreamString idx_name;
233 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
234
235 return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData()));
236 }
237
238 void
239 Clear ()
240 {
241 m_indexes = 0;
242 m_count = 0;
243 m_ptr_size = 0;
244 m_process = nullptr;
245 }
246
247 private:
248 uint64_t m_indexes;
249 size_t m_count;
250 uint32_t m_ptr_size;
251 Process *m_process;
252
253 // cfr. Foundation for the details of this code
254 size_t _lengthForInlinePayload(uint32_t ptr_size) {
255 m_ptr_size = ptr_size;
256 if (m_ptr_size == 8)
257 m_count = ((m_indexes >> 3) & 0x7);
258 else
259 m_count = ((m_indexes >> 3) & 0x3);
260 return m_count;
261 }
262
263 std::pair<uint64_t, bool>
264 _indexAtPositionForInlinePayload(size_t pos)
265 {
266 if (m_ptr_size == 8)
267 {
268 switch (pos) {
269 case 5: return {((m_indexes >> 51) & 0x1ff),true};
270 case 4: return {((m_indexes >> 42) & 0x1ff),true};
271 case 3: return {((m_indexes >> 33) & 0x1ff),true};
272 case 2: return {((m_indexes >> 24) & 0x1ff),true};
273 case 1: return {((m_indexes >> 15) & 0x1ff),true};
274 case 0: return {((m_indexes >> 6) & 0x1ff),true};
275 }
276 }
277 else
278 {
279 switch (pos) {
280 case 2: return {((m_indexes >> 23) & 0x1ff),true};
281 case 1: return {((m_indexes >> 14) & 0x1ff),true};
282 case 0: return {((m_indexes >> 5) & 0x1ff),true};
283 }
284 }
285 return {0,false};
286 }
287
288 };
Eric Christopher098f8982014-10-21 20:39:34 +0000289 struct OutsourcedIndexes {
Enrico Granata7569f232015-06-16 20:48:49 +0000290 ValueObject *m_indexes;
291 size_t m_count;
292
293 lldb::ValueObjectSP
294 GetIndexAtIndex (size_t idx)
295 {
296 if (m_indexes)
297 {
298 ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
299 return index_sp;
300 }
301 return nullptr;
302 }
303
304 void
305 Clear ()
306 {
307 m_indexes = nullptr;
308 m_count = 0;
309 }
310 };
Eric Christopher098f8982014-10-21 20:39:34 +0000311
312 union {
Enrico Granata7569f232015-06-16 20:48:49 +0000313 struct InlinedIndexes m_inlined;
314 struct OutsourcedIndexes m_outsourced;
Enrico Granata5510a572014-10-15 21:38:32 +0000315 };
Enrico Granata7569f232015-06-16 20:48:49 +0000316
317 void
318 Clear ()
319 {
320 m_mode = Mode::Invalid;
321 m_inlined.Clear();
322 m_outsourced.Clear();
323 }
Enrico Granata5510a572014-10-15 21:38:32 +0000324 } m_impl;
325
326 uint32_t m_ptr_size;
327 ClangASTContext* m_ast_ctx;
Greg Claytona1e5dc82015-08-11 22:53:00 +0000328 CompilerType m_uint_star_type;
Enrico Granata5510a572014-10-15 21:38:32 +0000329};
330
331namespace lldb_private {
332 namespace formatters {
333
334 SyntheticChildrenFrontEnd* NSIndexPathSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
335 {
336 if (valobj_sp)
337 return new NSIndexPathSyntheticFrontEnd(valobj_sp);
338 return nullptr;
339 }
340 }
341}