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