1 //===-- NSArray.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/lldb-python.h"
11
12 #include "lldb/DataFormatters/CXXFormatterFunctions.h"
13
14 #include "lldb/Core/DataBufferHeap.h"
15 #include "lldb/Core/Error.h"
16 #include "lldb/Core/Stream.h"
17 #include "lldb/Core/ValueObject.h"
18 #include "lldb/Core/ValueObjectConstResult.h"
19 #include "lldb/Host/Endian.h"
20 #include "lldb/Symbol/ClangASTContext.h"
21 #include "lldb/Target/ObjCLanguageRuntime.h"
22 #include "lldb/Target/Target.h"
23
24 using namespace lldb;
25 using namespace lldb_private;
26 using namespace lldb_private::formatters;
27
28 bool
NSArraySummaryProvider(ValueObject & valobj,Stream & stream)29 lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream)
30 {
31 ProcessSP process_sp = valobj.GetProcessSP();
32 if (!process_sp)
33 return false;
34
35 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
36
37 if (!runtime)
38 return false;
39
40 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
41
42 if (!descriptor.get() || !descriptor->IsValid())
43 return false;
44
45 uint32_t ptr_size = process_sp->GetAddressByteSize();
46
47 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
48
49 if (!valobj_addr)
50 return false;
51
52 uint64_t value = 0;
53
54 const char* class_name = descriptor->GetClassName().GetCString();
55
56 if (!class_name || !*class_name)
57 return false;
58
59 if (!strcmp(class_name,"__NSArrayI"))
60 {
61 Error error;
62 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
63 if (error.Fail())
64 return false;
65 }
66 else if (!strcmp(class_name,"__NSArrayM"))
67 {
68 Error error;
69 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
70 if (error.Fail())
71 return false;
72 }
73 else if (!strcmp(class_name,"__NSCFArray"))
74 {
75 Error error;
76 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error);
77 if (error.Fail())
78 return false;
79 }
80 else
81 {
82 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
83 return false;
84 }
85
86 stream.Printf("@\"%" PRIu64 " object%s\"",
87 value,
88 value == 1 ? "" : "s");
89 return true;
90 }
91
NSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)92 lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
93 SyntheticChildrenFrontEnd(*valobj_sp.get()),
94 m_exe_ctx_ref(),
95 m_ptr_size(8),
96 m_data_32(NULL),
97 m_data_64(NULL)
98 {
99 if (valobj_sp)
100 {
101 clang::ASTContext *ast = valobj_sp->GetClangType().GetASTContext();
102 if (ast)
103 m_id_type = ClangASTType(ast, ast->ObjCBuiltinIdTy);
104 }
105 }
106
107 size_t
CalculateNumChildren()108 lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren ()
109 {
110 if (m_data_32)
111 return m_data_32->_used;
112 if (m_data_64)
113 return m_data_64->_used;
114 return 0;
115 }
116
117 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)118 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
119 {
120 if (!m_data_32 && !m_data_64)
121 return lldb::ValueObjectSP();
122 if (idx >= CalculateNumChildren())
123 return lldb::ValueObjectSP();
124 lldb::addr_t object_at_idx = (m_data_32 ? m_data_32->_data : m_data_64->_data);
125 size_t pyhs_idx = idx;
126 pyhs_idx += (m_data_32 ? m_data_32->offset : m_data_64->offset);
127 if ((m_data_32 ? m_data_32->_size : m_data_64->_size) <= pyhs_idx)
128 pyhs_idx -= (m_data_32 ? m_data_32->_size : m_data_64->_size);
129 object_at_idx += (pyhs_idx * m_ptr_size);
130 StreamString idx_name;
131 idx_name.Printf("[%zu]",idx);
132 lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(),
133 object_at_idx,
134 m_exe_ctx_ref,
135 m_id_type);
136 m_children.push_back(retval_sp);
137 return retval_sp;
138 }
139
140 bool
Update()141 lldb_private::formatters::NSArrayMSyntheticFrontEnd::Update()
142 {
143 m_children.clear();
144 ValueObjectSP valobj_sp = m_backend.GetSP();
145 m_ptr_size = 0;
146 delete m_data_32;
147 m_data_32 = NULL;
148 delete m_data_64;
149 m_data_64 = NULL;
150 if (!valobj_sp)
151 return false;
152 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
153 Error error;
154 error.Clear();
155 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
156 if (!process_sp)
157 return false;
158 m_ptr_size = process_sp->GetAddressByteSize();
159 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
160 if (m_ptr_size == 4)
161 {
162 m_data_32 = new DataDescriptor_32();
163 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
164 }
165 else
166 {
167 m_data_64 = new DataDescriptor_64();
168 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
169 }
170 if (error.Fail())
171 return false;
172 return false;
173 }
174
175 bool
MightHaveChildren()176 lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren ()
177 {
178 return true;
179 }
180
181 size_t
GetIndexOfChildWithName(const ConstString & name)182 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
183 {
184 if (!m_data_32 && !m_data_64)
185 return UINT32_MAX;
186 const char* item_name = name.GetCString();
187 uint32_t idx = ExtractIndexFromString(item_name);
188 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
189 return UINT32_MAX;
190 return idx;
191 }
192
~NSArrayMSyntheticFrontEnd()193 lldb_private::formatters::NSArrayMSyntheticFrontEnd::~NSArrayMSyntheticFrontEnd ()
194 {
195 delete m_data_32;
196 m_data_32 = NULL;
197 delete m_data_64;
198 m_data_64 = NULL;
199 }
200
NSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)201 lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
202 SyntheticChildrenFrontEnd (*valobj_sp.get()),
203 m_exe_ctx_ref (),
204 m_ptr_size (8),
205 m_items (0),
206 m_data_ptr (0)
207 {
208 if (valobj_sp)
209 {
210 clang::ASTContext *ast = valobj_sp->GetClangType().GetASTContext();
211 if (ast)
212 m_id_type = ClangASTType(ast, ast->ObjCBuiltinIdTy);
213 }
214 }
215
~NSArrayISyntheticFrontEnd()216 lldb_private::formatters::NSArrayISyntheticFrontEnd::~NSArrayISyntheticFrontEnd ()
217 {
218 }
219
220 size_t
GetIndexOfChildWithName(const ConstString & name)221 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
222 {
223 const char* item_name = name.GetCString();
224 uint32_t idx = ExtractIndexFromString(item_name);
225 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
226 return UINT32_MAX;
227 return idx;
228 }
229
230 size_t
CalculateNumChildren()231 lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren ()
232 {
233 return m_items;
234 }
235
236 bool
Update()237 lldb_private::formatters::NSArrayISyntheticFrontEnd::Update()
238 {
239 m_ptr_size = 0;
240 m_items = 0;
241 m_data_ptr = 0;
242 m_children.clear();
243 ValueObjectSP valobj_sp = m_backend.GetSP();
244 if (!valobj_sp)
245 return false;
246 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
247 Error error;
248 error.Clear();
249 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
250 if (!process_sp)
251 return false;
252 m_ptr_size = process_sp->GetAddressByteSize();
253 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
254 m_items = process_sp->ReadPointerFromMemory(data_location, error);
255 if (error.Fail())
256 return false;
257 m_data_ptr = data_location+m_ptr_size;
258 return false;
259 }
260
261 bool
MightHaveChildren()262 lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren ()
263 {
264 return true;
265 }
266
267 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)268 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx)
269 {
270 if (idx >= CalculateNumChildren())
271 return lldb::ValueObjectSP();
272 lldb::addr_t object_at_idx = m_data_ptr;
273 object_at_idx += (idx * m_ptr_size);
274 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
275 if (!process_sp)
276 return lldb::ValueObjectSP();
277 Error error;
278 if (error.Fail())
279 return lldb::ValueObjectSP();
280 StreamString idx_name;
281 idx_name.Printf("[%zu]",idx);
282 lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), object_at_idx, m_exe_ctx_ref, m_id_type);
283 m_children.push_back(retval_sp);
284 return retval_sp;
285 }
286
NSArraySyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)287 SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
288 {
289 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
290 if (!process_sp)
291 return NULL;
292 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
293 if (!runtime)
294 return NULL;
295
296 if (!valobj_sp->IsPointerType())
297 {
298 Error error;
299 valobj_sp = valobj_sp->AddressOf(error);
300 if (error.Fail() || !valobj_sp)
301 return NULL;
302 }
303
304 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
305
306 if (!descriptor.get() || !descriptor->IsValid())
307 return NULL;
308
309 const char* class_name = descriptor->GetClassName().GetCString();
310
311 if (!class_name || !*class_name)
312 return NULL;
313
314 if (!strcmp(class_name,"__NSArrayI"))
315 {
316 return (new NSArrayISyntheticFrontEnd(valobj_sp));
317 }
318 else if (!strcmp(class_name,"__NSArrayM"))
319 {
320 return (new NSArrayMSyntheticFrontEnd(valobj_sp));
321 }
322 else
323 {
324 return (new NSArrayCodeRunningSyntheticFrontEnd(valobj_sp));
325 }
326 }
327
NSArrayCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)328 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
329 SyntheticChildrenFrontEnd(*valobj_sp.get())
330 {}
331
332 size_t
CalculateNumChildren()333 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
334 {
335 uint64_t count = 0;
336 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
337 return count;
338 return 0;
339 }
340
341 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)342 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
343 {
344 StreamString idx_name;
345 idx_name.Printf("[%zu]",idx);
346 lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx);
347 if (valobj_sp)
348 valobj_sp->SetName(ConstString(idx_name.GetData()));
349 return valobj_sp;
350 }
351
352 bool
Update()353 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::Update()
354 {
355 return false;
356 }
357
358 bool
MightHaveChildren()359 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::MightHaveChildren ()
360 {
361 return true;
362 }
363
364 size_t
GetIndexOfChildWithName(const ConstString & name)365 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
366 {
367 return 0;
368 }
369
~NSArrayCodeRunningSyntheticFrontEnd()370 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::~NSArrayCodeRunningSyntheticFrontEnd ()
371 {}
372