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