blob: 4e2c0663766dae260515e5886c421bbe447f769c [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
Enrico Granata170c3952015-09-14 22:18:32 +000010#include "Cocoa.h"
Enrico Granata5510a572014-10-15 21:38:32 +000011
12#include "lldb/Core/ValueObject.h"
13#include "lldb/Core/ValueObjectConstResult.h"
Enrico Granata419d7912015-09-04 00:33:51 +000014#include "lldb/DataFormatters/FormattersHelpers.h"
Enrico Granata5510a572014-10-15 21:38:32 +000015#include "lldb/DataFormatters/TypeSynthetic.h"
16#include "lldb/Target/ObjCLanguageRuntime.h"
17#include "lldb/Target/Process.h"
18#include "lldb/Symbol/ClangASTContext.h"
19
20using namespace lldb;
21using namespace lldb_private;
22using namespace lldb_private::formatters;
23
24class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd
25{
26public:
27 NSIndexPathSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
28 SyntheticChildrenFrontEnd (*valobj_sp.get()),
29 m_ptr_size(0),
Enrico Granata5510a572014-10-15 21:38:32 +000030 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 Clayton99558cc42015-08-24 23:46:31 +000052 TypeSystem* type_system = m_backend.GetCompilerType().GetTypeSystem();
Greg Claytond8d4a572015-08-11 21:38:15 +000053 if (!type_system)
54 return false;
Greg Claytonf73034f2015-09-08 18:15:05 +000055
56 ClangASTContext *ast = m_backend.GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext();
57 if (!ast)
Enrico Granata5510a572014-10-15 21:38:32 +000058 return false;
Greg Claytonf73034f2015-09-08 18:15:05 +000059
60 m_uint_star_type = ast->GetPointerSizedIntType(false);
Enrico Granata5510a572014-10-15 21:38:32 +000061
62 static ConstString g__indexes("_indexes");
63 static ConstString g__length("_length");
64
65 ProcessSP process_sp = m_backend.GetProcessSP();
66 if (!process_sp)
67 return false;
68
69 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
70
71 if (!runtime)
72 return false;
73
74 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(m_backend));
75
76 if (!descriptor.get() || !descriptor->IsValid())
77 return false;
78
79 uint64_t info_bits(0),value_bits(0),payload(0);
80
81 if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload))
82 {
Enrico Granata5510a572014-10-15 21:38:32 +000083 m_impl.m_inlined.SetIndexes(payload, *process_sp);
Enrico Granata7569f232015-06-16 20:48:49 +000084 m_impl.m_mode = Mode::Inlined;
Enrico Granata5510a572014-10-15 21:38:32 +000085 }
86 else
87 {
88 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
89 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
90
91 bool has_indexes(false),has_length(false);
92
Zachary Turner225cc302015-01-09 20:15:03 +000093 for (size_t x = 0;
Enrico Granata5510a572014-10-15 21:38:32 +000094 x < descriptor->GetNumIVars();
95 x++)
96 {
97 const auto& ivar = descriptor->GetIVarAtIndex(x);
98 if (ivar.m_name == g__indexes)
99 {
100 _indexes_id = ivar;
101 has_indexes = true;
102 }
103 else if (ivar.m_name == g__length)
104 {
105 _length_id = ivar;
106 has_length = true;
107 }
108
109 if (has_length && has_indexes)
110 break;
111 }
112
113 if (has_length && has_indexes)
114 {
115 m_impl.m_outsourced.m_indexes = m_backend.GetSyntheticChildAtOffset(_indexes_id.m_offset,
116 m_uint_star_type.GetPointerType(),
117 true).get();
118 ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(_length_id.m_offset,
119 m_uint_star_type,
120 true));
121 if (length_sp)
122 {
123 m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
124 if (m_impl.m_outsourced.m_indexes)
125 m_impl.m_mode = Mode::Outsourced;
126 }
127 }
128 }
129 return false;
130 }
131
132 virtual bool
133 MightHaveChildren ()
134 {
135 if (m_impl.m_mode == Mode::Invalid)
136 return false;
137 return true;
138 }
139
140 virtual size_t
141 GetIndexOfChildWithName (const ConstString &name)
142 {
143 const char* item_name = name.GetCString();
144 uint32_t idx = ExtractIndexFromString(item_name);
145 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
146 return UINT32_MAX;
147 return idx;
148 }
149
150 virtual lldb::ValueObjectSP
151 GetSyntheticValue () { return nullptr; }
152
153 virtual
154 ~NSIndexPathSyntheticFrontEnd () {}
155
156protected:
157 ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
158
159 enum class Mode {
160 Inlined,
161 Outsourced,
162 Invalid
163 };
164
165 struct Impl {
166 Mode m_mode;
167
168 size_t
169 GetNumIndexes ()
170 {
171 switch (m_mode)
172 {
173 case Mode::Inlined:
174 return m_inlined.GetNumIndexes();
175 case Mode::Outsourced:
176 return m_outsourced.m_count;
177 default:
178 return 0;
179 }
180 }
181
182 lldb::ValueObjectSP
Greg Claytona1e5dc82015-08-11 22:53:00 +0000183 GetIndexAtIndex (size_t idx, const CompilerType& desired_type)
Enrico Granata5510a572014-10-15 21:38:32 +0000184 {
185 if (idx >= GetNumIndexes())
186 return nullptr;
187 switch (m_mode)
188 {
189 default: return nullptr;
190 case Mode::Inlined:
191 return m_inlined.GetIndexAtIndex (idx, desired_type);
192 case Mode::Outsourced:
193 return m_outsourced.GetIndexAtIndex (idx);
194 }
195 }
Enrico Granata5510a572014-10-15 21:38:32 +0000196
Eric Christopher098f8982014-10-21 20:39:34 +0000197 struct InlinedIndexes {
Enrico Granata7569f232015-06-16 20:48:49 +0000198 public:
199 void SetIndexes(uint64_t value, Process& p)
200 {
201 m_indexes = value;
202 _lengthForInlinePayload(p.GetAddressByteSize());
203 m_process = &p;
204 }
205
206 size_t
207 GetNumIndexes ()
208 {
209 return m_count;
210 }
Eric Christopher098f8982014-10-21 20:39:34 +0000211
Enrico Granata7569f232015-06-16 20:48:49 +0000212 lldb::ValueObjectSP
Greg Claytona1e5dc82015-08-11 22:53:00 +0000213 GetIndexAtIndex (size_t idx, const CompilerType& desired_type)
Enrico Granata7569f232015-06-16 20:48:49 +0000214 {
215 std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
216 if (!value.second)
217 return nullptr;
218
219 Value v;
220 if (m_ptr_size == 8)
221 {
222 Scalar scalar( (unsigned long long)value.first );
223 v = Value(scalar);
224 }
225 else
226 {
227 Scalar scalar( (unsigned int)value.first );
228 v = Value(scalar);
229 }
230
Greg Clayton99558cc42015-08-24 23:46:31 +0000231 v.SetCompilerType(desired_type);
Enrico Granata7569f232015-06-16 20:48:49 +0000232
233 StreamString idx_name;
234 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
235
236 return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData()));
237 }
238
239 void
240 Clear ()
241 {
242 m_indexes = 0;
243 m_count = 0;
244 m_ptr_size = 0;
245 m_process = nullptr;
246 }
247
248 private:
249 uint64_t m_indexes;
250 size_t m_count;
251 uint32_t m_ptr_size;
252 Process *m_process;
253
254 // cfr. Foundation for the details of this code
255 size_t _lengthForInlinePayload(uint32_t ptr_size) {
256 m_ptr_size = ptr_size;
257 if (m_ptr_size == 8)
258 m_count = ((m_indexes >> 3) & 0x7);
259 else
260 m_count = ((m_indexes >> 3) & 0x3);
261 return m_count;
262 }
263
264 std::pair<uint64_t, bool>
265 _indexAtPositionForInlinePayload(size_t pos)
266 {
267 if (m_ptr_size == 8)
268 {
269 switch (pos) {
270 case 5: return {((m_indexes >> 51) & 0x1ff),true};
271 case 4: return {((m_indexes >> 42) & 0x1ff),true};
272 case 3: return {((m_indexes >> 33) & 0x1ff),true};
273 case 2: return {((m_indexes >> 24) & 0x1ff),true};
274 case 1: return {((m_indexes >> 15) & 0x1ff),true};
275 case 0: return {((m_indexes >> 6) & 0x1ff),true};
276 }
277 }
278 else
279 {
280 switch (pos) {
281 case 2: return {((m_indexes >> 23) & 0x1ff),true};
282 case 1: return {((m_indexes >> 14) & 0x1ff),true};
283 case 0: return {((m_indexes >> 5) & 0x1ff),true};
284 }
285 }
286 return {0,false};
287 }
288
289 };
Eric Christopher098f8982014-10-21 20:39:34 +0000290 struct OutsourcedIndexes {
Enrico Granata7569f232015-06-16 20:48:49 +0000291 ValueObject *m_indexes;
292 size_t m_count;
293
294 lldb::ValueObjectSP
295 GetIndexAtIndex (size_t idx)
296 {
297 if (m_indexes)
298 {
299 ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
300 return index_sp;
301 }
302 return nullptr;
303 }
304
305 void
306 Clear ()
307 {
308 m_indexes = nullptr;
309 m_count = 0;
310 }
311 };
Eric Christopher098f8982014-10-21 20:39:34 +0000312
313 union {
Enrico Granata7569f232015-06-16 20:48:49 +0000314 struct InlinedIndexes m_inlined;
315 struct OutsourcedIndexes m_outsourced;
Enrico Granata5510a572014-10-15 21:38:32 +0000316 };
Enrico Granata7569f232015-06-16 20:48:49 +0000317
318 void
319 Clear ()
320 {
321 m_mode = Mode::Invalid;
322 m_inlined.Clear();
323 m_outsourced.Clear();
324 }
Enrico Granata5510a572014-10-15 21:38:32 +0000325 } m_impl;
326
327 uint32_t m_ptr_size;
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}