blob: ee9583ef4cc1a37775f54c732a10ec95ec1bfae1 [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 {
50 m_impl.m_mode = Mode::Invalid;
51
52 m_ast_ctx = ClangASTContext::GetASTContext(m_backend.GetClangType().GetASTContext());
53 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 {
79 m_impl.m_mode = Mode::Inlined;
80 m_impl.m_inlined.SetIndexes(payload, *process_sp);
81 }
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 {
194 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 }
207
208 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 Value v;
215 if (m_ptr_size == 8)
216 {
217 Scalar scalar( (unsigned long long)value.first );
218 v = Value(scalar);
219 }
220 else
221 {
222 Scalar scalar( (unsigned int)value.first );
223 v = Value(scalar);
224 }
225 v.SetClangType(desired_type);
226 StreamString idx_name;
227 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
228 return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData()));
229 }
Enrico Granata5510a572014-10-15 21:38:32 +0000230
Eric Christopher098f8982014-10-21 20:39:34 +0000231 private:
232 uint64_t m_indexes;
233 size_t m_count;
234 uint32_t m_ptr_size;
235 Process *m_process;
236
237 // cfr. Foundation for the details of this code
238 size_t _lengthForInlinePayload(uint32_t ptr_size) {
239 m_ptr_size = ptr_size;
240 if (m_ptr_size == 8)
241 m_count = ((m_indexes >> 3) & 0x7);
242 else
243 m_count = ((m_indexes >> 3) & 0x3);
244 return m_count;
245 }
246
247 std::pair<uint64_t, bool>
248 _indexAtPositionForInlinePayload(size_t pos) {
249 if (m_ptr_size == 8)
250 {
251 switch (pos) {
252 case 5: return {((m_indexes >> 51) & 0x1ff),true};
253 case 4: return {((m_indexes >> 42) & 0x1ff),true};
254 case 3: return {((m_indexes >> 33) & 0x1ff),true};
255 case 2: return {((m_indexes >> 24) & 0x1ff),true};
256 case 1: return {((m_indexes >> 15) & 0x1ff),true};
257 case 0: return {((m_indexes >> 6) & 0x1ff),true};
258 }
259 }
260 else
261 {
262 switch (pos) {
263 case 2: return {((m_indexes >> 23) & 0x1ff),true};
264 case 1: return {((m_indexes >> 14) & 0x1ff),true};
265 case 0: return {((m_indexes >> 5) & 0x1ff),true};
266 }
267 }
268 return {0,false};
269 }
270
271 };
272 struct OutsourcedIndexes {
273 ValueObject *m_indexes;
274 size_t m_count;
275
276 lldb::ValueObjectSP
277 GetIndexAtIndex (size_t idx)
278 {
279 if (m_indexes)
280 {
281 ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMemberFromPointer(idx, true));
282 return index_sp;
283 }
284 return nullptr;
285 }
286 };
287
288 union {
289 struct InlinedIndexes m_inlined;
290 struct OutsourcedIndexes m_outsourced;
Enrico Granata5510a572014-10-15 21:38:32 +0000291 };
292 } m_impl;
293
294 uint32_t m_ptr_size;
295 ClangASTContext* m_ast_ctx;
296 ClangASTType m_uint_star_type;
297};
298
299namespace lldb_private {
300 namespace formatters {
301
302 SyntheticChildrenFrontEnd* NSIndexPathSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
303 {
304 if (valobj_sp)
305 return new NSIndexPathSyntheticFrontEnd(valobj_sp);
306 return nullptr;
307 }
308 }
309}