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