blob: 3c7c003ed95ac46ddaafcb79348abf9a0943c390 [file] [log] [blame]
Enrico Granataf615b802013-02-15 23:38:37 +00001//===-- NSSet.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
Matt Kopec676a4872013-02-21 23:55:31 +000010#include "lldb/lldb-python.h"
11
Enrico Granataf615b802013-02-15 23:38:37 +000012#include "lldb/DataFormatters/CXXFormatterFunctions.h"
13
Enrico Granataf615b802013-02-15 23:38:37 +000014#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
24using namespace lldb;
25using namespace lldb_private;
26using namespace lldb_private::formatters;
27
28template<bool cf_style>
29bool
30lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream)
31{
32 ProcessSP process_sp = valobj.GetProcessSP();
33 if (!process_sp)
34 return false;
35
36 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
37
38 if (!runtime)
39 return false;
40
41 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
42
43 if (!descriptor.get() || !descriptor->IsValid())
44 return false;
45
46 uint32_t ptr_size = process_sp->GetAddressByteSize();
47 bool is_64bit = (ptr_size == 8);
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,"__NSSetI"))
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 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
68 }
69 else if (!strcmp(class_name,"__NSSetM"))
70 {
71 Error error;
72 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
73 if (error.Fail())
74 return false;
75 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
76 }
Enrico Granataea9f9e82013-07-15 23:17:32 +000077 /*else if (!strcmp(class_name,"__NSCFSet"))
Enrico Granataf615b802013-02-15 23:38:37 +000078 {
79 Error error;
Enrico Granataf68f7322013-03-15 18:44:08 +000080 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
Enrico Granataf615b802013-02-15 23:38:37 +000081 if (error.Fail())
82 return false;
83 if (is_64bit)
84 value &= ~0x1fff000000000000UL;
85 }
Enrico Granataea9f9e82013-07-15 23:17:32 +000086 else if (!strcmp(class_name,"NSCountedSet"))
Enrico Granataf615b802013-02-15 23:38:37 +000087 {
88 Error error;
89 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
90 if (error.Fail())
91 return false;
Enrico Granataf68f7322013-03-15 18:44:08 +000092 value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 : 12), 4, 0, error);
Enrico Granataf615b802013-02-15 23:38:37 +000093 if (error.Fail())
94 return false;
95 if (is_64bit)
96 value &= ~0x1fff000000000000UL;
Enrico Granataf68f7322013-03-15 18:44:08 +000097 }*/
Enrico Granataf615b802013-02-15 23:38:37 +000098 else
99 {
100 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
101 return false;
102 }
103
104 stream.Printf("%s%" PRIu64 " %s%s",
105 (cf_style ? "@\"" : ""),
106 value,
107 (cf_style ? (value == 1 ? "value" : "values") : (value == 1 ? "object" : "objects")),
108 (cf_style ? "\"" : ""));
109 return true;
110}
111
Enrico Granata9f02e092013-02-18 23:16:23 +0000112SyntheticChildrenFrontEnd* lldb_private::formatters::NSSetSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
113{
114 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
115 if (!process_sp)
116 return NULL;
117 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
118 if (!runtime)
119 return NULL;
120
121 if (!valobj_sp->IsPointerType())
122 {
123 Error error;
124 valobj_sp = valobj_sp->AddressOf(error);
125 if (error.Fail() || !valobj_sp)
126 return NULL;
127 }
128
129 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
130
131 if (!descriptor.get() || !descriptor->IsValid())
132 return NULL;
133
134 const char* class_name = descriptor->GetClassName().GetCString();
135
136 if (!class_name || !*class_name)
137 return NULL;
138
139 if (!strcmp(class_name,"__NSSetI"))
140 {
141 return (new NSSetISyntheticFrontEnd(valobj_sp));
142 }
143 else if (!strcmp(class_name,"__NSSetM"))
144 {
145 return (new NSSetMSyntheticFrontEnd(valobj_sp));
146 }
Enrico Granatacd67f972013-04-27 00:27:20 +0000147 else if ((!strcmp(class_name,"__NSOrderedSetI")) || (!strcmp(class_name,"__NSOrderedSetM")))
148 {
149 return new NSOrderedSetSyntheticFrontEnd(valobj_sp); // this runs code
150 }
Enrico Granata9f02e092013-02-18 23:16:23 +0000151 else
152 {
153 return /*(new NSSetCodeRunningSyntheticFrontEnd(valobj_sp))*/ NULL;
154 }
155}
156
157lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
158SyntheticChildrenFrontEnd(*valobj_sp.get()),
159m_exe_ctx_ref(),
160m_ptr_size(8),
161m_data_32(NULL),
162m_data_64(NULL)
163{
164 if (valobj_sp)
165 Update();
166}
167
168lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd ()
169{
170 delete m_data_32;
171 m_data_32 = NULL;
172 delete m_data_64;
173 m_data_64 = NULL;
174}
175
176size_t
177lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
178{
179 const char* item_name = name.GetCString();
180 uint32_t idx = ExtractIndexFromString(item_name);
181 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
182 return UINT32_MAX;
183 return idx;
184}
185
186size_t
187lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren ()
188{
189 if (!m_data_32 && !m_data_64)
190 return 0;
191 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
192}
193
194bool
195lldb_private::formatters::NSSetISyntheticFrontEnd::Update()
196{
197 m_children.clear();
198 delete m_data_32;
199 m_data_32 = NULL;
200 delete m_data_64;
201 m_data_64 = NULL;
202 m_ptr_size = 0;
203 ValueObjectSP valobj_sp = m_backend.GetSP();
204 if (!valobj_sp)
205 return false;
Enrico Granata9f02e092013-02-18 23:16:23 +0000206 if (!valobj_sp)
207 return false;
208 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
209 Error error;
210 if (valobj_sp->IsPointerType())
211 {
212 valobj_sp = valobj_sp->Dereference(error);
213 if (error.Fail() || !valobj_sp)
214 return false;
215 }
216 error.Clear();
217 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
218 if (!process_sp)
219 return false;
220 m_ptr_size = process_sp->GetAddressByteSize();
221 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
222 if (m_ptr_size == 4)
223 {
224 m_data_32 = new DataDescriptor_32();
225 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
226 }
227 else
228 {
229 m_data_64 = new DataDescriptor_64();
230 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
231 }
232 if (error.Fail())
233 return false;
234 m_data_ptr = data_location + m_ptr_size;
235 return false;
236}
237
238bool
239lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren ()
240{
241 return true;
242}
243
244lldb::ValueObjectSP
245lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx)
246{
247 uint32_t num_children = CalculateNumChildren();
248
249 if (idx >= num_children)
250 return lldb::ValueObjectSP();
251
Enrico Granata5383e812013-11-21 01:08:05 +0000252 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
253 if (!process_sp)
254 return lldb::ValueObjectSP();
255
Enrico Granata9f02e092013-02-18 23:16:23 +0000256 if (m_children.empty())
257 {
258 // do the scan phase
259 lldb::addr_t obj_at_idx = 0;
260
261 uint32_t tries = 0;
262 uint32_t test_idx = 0;
263
264 while(tries < num_children)
265 {
266 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
Enrico Granata9f02e092013-02-18 23:16:23 +0000267 if (!process_sp)
268 return lldb::ValueObjectSP();
269 Error error;
270 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
271 if (error.Fail())
272 return lldb::ValueObjectSP();
273
274 test_idx++;
275
276 if (!obj_at_idx)
277 continue;
278 tries++;
279
280 SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()};
281
282 m_children.push_back(descriptor);
283 }
284 }
285
286 if (idx >= m_children.size()) // should never happen
287 return lldb::ValueObjectSP();
288
289 SetItemDescriptor &set_item = m_children[idx];
290 if (!set_item.valobj_sp)
291 {
Enrico Granata5383e812013-11-21 01:08:05 +0000292 auto ptr_size = process_sp->GetAddressByteSize();
293 DataBufferHeap buffer(ptr_size,0);
294 switch (ptr_size)
295 {
296 case 0: // architecture has no clue?? - fail
297 return lldb::ValueObjectSP();
298 case 4:
299 *((uint32_t*)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
300 break;
301 case 8:
302 *((uint64_t*)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
303 break;
304 default:
305 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
306 }
Enrico Granata9f02e092013-02-18 23:16:23 +0000307 StreamString idx_name;
Deepak Panickal99fbc072014-03-03 15:39:47 +0000308 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
Enrico Granata5383e812013-11-21 01:08:05 +0000309
310 DataExtractor data(buffer.GetBytes(),
311 buffer.GetByteSize(),
312 process_sp->GetByteOrder(),
313 process_sp->GetAddressByteSize());
314
315 set_item.valobj_sp =
316 ValueObject::CreateValueObjectFromData(idx_name.GetData(),
317 data,
318 m_exe_ctx_ref,
319 m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
Enrico Granata9f02e092013-02-18 23:16:23 +0000320 }
321 return set_item.valobj_sp;
322}
323
324lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
325SyntheticChildrenFrontEnd(*valobj_sp.get()),
326m_exe_ctx_ref(),
327m_ptr_size(8),
328m_data_32(NULL),
329m_data_64(NULL)
330{
331 if (valobj_sp)
332 Update ();
333}
334
335lldb_private::formatters::NSSetMSyntheticFrontEnd::~NSSetMSyntheticFrontEnd ()
336{
337 delete m_data_32;
338 m_data_32 = NULL;
339 delete m_data_64;
340 m_data_64 = NULL;
341}
342
343size_t
344lldb_private::formatters::NSSetMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
345{
346 const char* item_name = name.GetCString();
347 uint32_t idx = ExtractIndexFromString(item_name);
348 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
349 return UINT32_MAX;
350 return idx;
351}
352
353size_t
354lldb_private::formatters::NSSetMSyntheticFrontEnd::CalculateNumChildren ()
355{
356 if (!m_data_32 && !m_data_64)
357 return 0;
358 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
359}
360
361bool
362lldb_private::formatters::NSSetMSyntheticFrontEnd::Update()
363{
364 m_children.clear();
365 ValueObjectSP valobj_sp = m_backend.GetSP();
366 m_ptr_size = 0;
367 delete m_data_32;
368 m_data_32 = NULL;
369 delete m_data_64;
370 m_data_64 = NULL;
371 if (!valobj_sp)
372 return false;
Enrico Granata9f02e092013-02-18 23:16:23 +0000373 if (!valobj_sp)
374 return false;
375 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
376 Error error;
377 if (valobj_sp->IsPointerType())
378 {
379 valobj_sp = valobj_sp->Dereference(error);
380 if (error.Fail() || !valobj_sp)
381 return false;
382 }
383 error.Clear();
384 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
385 if (!process_sp)
386 return false;
387 m_ptr_size = process_sp->GetAddressByteSize();
388 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
389 if (m_ptr_size == 4)
390 {
391 m_data_32 = new DataDescriptor_32();
392 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
393 }
394 else
395 {
396 m_data_64 = new DataDescriptor_64();
397 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
398 }
399 if (error.Fail())
400 return false;
401 return false;
402}
403
404bool
405lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren ()
406{
407 return true;
408}
409
410lldb::ValueObjectSP
411lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
412{
413 lldb::addr_t m_objs_addr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
414
415 uint32_t num_children = CalculateNumChildren();
416
417 if (idx >= num_children)
418 return lldb::ValueObjectSP();
419
Enrico Granata5383e812013-11-21 01:08:05 +0000420 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
421 if (!process_sp)
422 return lldb::ValueObjectSP();
423
Enrico Granata9f02e092013-02-18 23:16:23 +0000424 if (m_children.empty())
425 {
426 // do the scan phase
427 lldb::addr_t obj_at_idx = 0;
428
429 uint32_t tries = 0;
430 uint32_t test_idx = 0;
431
432 while(tries < num_children)
433 {
434 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
Enrico Granata9f02e092013-02-18 23:16:23 +0000435 if (!process_sp)
436 return lldb::ValueObjectSP();
437 Error error;
438 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
439 if (error.Fail())
440 return lldb::ValueObjectSP();
441
442 test_idx++;
443
444 if (!obj_at_idx)
445 continue;
446 tries++;
447
448 SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()};
449
450 m_children.push_back(descriptor);
451 }
452 }
453
454 if (idx >= m_children.size()) // should never happen
455 return lldb::ValueObjectSP();
456
457 SetItemDescriptor &set_item = m_children[idx];
458 if (!set_item.valobj_sp)
459 {
Enrico Granata5383e812013-11-21 01:08:05 +0000460 auto ptr_size = process_sp->GetAddressByteSize();
461 DataBufferHeap buffer(ptr_size,0);
462 switch (ptr_size)
463 {
464 case 0: // architecture has no clue?? - fail
465 return lldb::ValueObjectSP();
466 case 4:
467 *((uint32_t*)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
468 break;
469 case 8:
470 *((uint64_t*)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
471 break;
472 default:
473 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
474 }
Enrico Granata9f02e092013-02-18 23:16:23 +0000475 StreamString idx_name;
Deepak Panickal99fbc072014-03-03 15:39:47 +0000476 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
Enrico Granata5383e812013-11-21 01:08:05 +0000477
478 DataExtractor data(buffer.GetBytes(),
479 buffer.GetByteSize(),
480 process_sp->GetByteOrder(),
481 process_sp->GetAddressByteSize());
482
483 set_item.valobj_sp =
484 ValueObject::CreateValueObjectFromData(idx_name.GetData(),
485 data,
486 m_exe_ctx_ref,
487 m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
Enrico Granata9f02e092013-02-18 23:16:23 +0000488 }
489 return set_item.valobj_sp;
490}
491
Enrico Granatacd67f972013-04-27 00:27:20 +0000492lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
493SyntheticChildrenFrontEnd(*valobj_sp.get()),
494m_count(UINT32_MAX),
495m_children()
496{}
497
498size_t
499lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::CalculateNumChildren ()
500{
501 if (m_count != UINT32_MAX)
502 return m_count;
503 uint64_t count_temp;
504 if (ExtractValueFromObjCExpression(m_backend,"unsigned int","count",count_temp))
505 return (m_count = count_temp);
506 return (m_count = 0);
507}
508
509lldb::ValueObjectSP
510lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetChildAtIndex (size_t idx)
511{
512 auto iter = m_children.find(idx);
513 if (iter == m_children.end())
514 {
515 lldb::ValueObjectSP retval_sp;
516 if (idx <= m_count)
517 {
518 retval_sp = CallSelectorOnObject(m_backend, "id", "objectAtIndex", idx);
519 if (retval_sp)
520 {
521 StreamString idx_name;
Deepak Panickal99fbc072014-03-03 15:39:47 +0000522 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
Enrico Granatacd67f972013-04-27 00:27:20 +0000523 retval_sp->SetName(ConstString(idx_name.GetData()));
524 }
525 m_children[idx] = retval_sp;
526 }
527 return retval_sp;
528 }
529 else
530 return iter->second;
531}
532
533bool
534lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::Update()
535{
536 return false;
537}
538
539bool
540lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::MightHaveChildren ()
541{
542 return true;
543}
544
545size_t
546lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
547{
548 const char* item_name = name.GetCString();
549 uint32_t idx = ExtractIndexFromString(item_name);
550 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
551 return UINT32_MAX;
552 return idx;
553}
554
555lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::~NSOrderedSetSyntheticFrontEnd ()
556{
557}
558
Enrico Granataf615b802013-02-15 23:38:37 +0000559template bool
560lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream);
561
562template bool
563lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream);