blob: 18f00cc395cb61fd3eb0d34af55458b87f35a8f3 [file] [log] [blame]
Enrico Granataea687532013-02-15 23:38:37 +00001//===-- NSDictionary.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
26template<bool name_entries>
27bool
28lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream)
29{
30 ProcessSP process_sp = valobj.GetProcessSP();
31 if (!process_sp)
32 return false;
33
34 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
35
36 if (!runtime)
37 return false;
38
39 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
40
41 if (!descriptor.get() || !descriptor->IsValid())
42 return false;
43
44 uint32_t ptr_size = process_sp->GetAddressByteSize();
45 bool is_64bit = (ptr_size == 8);
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,"__NSDictionaryI"))
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 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
66 }
67 else if (!strcmp(class_name,"__NSDictionaryM"))
68 {
69 Error error;
70 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
71 if (error.Fail())
72 return false;
73 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
74 }
75 else if (!strcmp(class_name,"__NSCFDictionary"))
76 {
77 Error error;
78 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), ptr_size, 0, error);
79 if (error.Fail())
80 return false;
81 if (is_64bit)
82 value &= ~0x0f1f000000000000UL;
83 }
84 else
85 {
86 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
87 return false;
88 }
89
90 stream.Printf("%s%" PRIu64 " %s%s",
91 (name_entries ? "@\"" : ""),
92 value,
93 (name_entries ? (value == 1 ? "entry" : "entries") : (value == 1 ? "key/value pair" : "key/value pairs")),
94 (name_entries ? "\"" : ""));
95 return true;
96}
97
98SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
99{
100
101 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
102 if (!process_sp)
103 return NULL;
104 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
105 if (!runtime)
106 return NULL;
107
108 if (!valobj_sp->IsPointerType())
109 {
110 Error error;
111 valobj_sp = valobj_sp->AddressOf(error);
112 if (error.Fail() || !valobj_sp)
113 return NULL;
114 }
115
116 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
117
118 if (!descriptor.get() || !descriptor->IsValid())
119 return NULL;
120
121 const char* class_name = descriptor->GetClassName().GetCString();
122
123 if (!class_name || !*class_name)
124 return NULL;
125
126 if (!strcmp(class_name,"__NSDictionaryI"))
127 {
128 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
129 }
130 else if (!strcmp(class_name,"__NSDictionaryM"))
131 {
132 return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
133 }
134 else
135 {
136 return (new NSDictionaryCodeRunningSyntheticFrontEnd(valobj_sp));
137 }
138}
139
140lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
141SyntheticChildrenFrontEnd(*valobj_sp.get())
142{}
143
144size_t
145lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
146{
147 uint64_t count = 0;
148 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
149 return count;
150 return 0;
151}
152
153lldb::ValueObjectSP
154lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
155{
156 StreamString idx_name;
157 idx_name.Printf("[%zu]",idx);
158 StreamString valobj_expr_path;
159 m_backend.GetExpressionPath(valobj_expr_path, false);
160 StreamString key_fetcher_expr;
161 key_fetcher_expr.Printf("(id)[(NSArray*)[%s allKeys] objectAtIndex:%zu]",valobj_expr_path.GetData(),idx);
162 StreamString value_fetcher_expr;
163 value_fetcher_expr.Printf("(id)[%s objectForKey:%s]",valobj_expr_path.GetData(),key_fetcher_expr.GetData());
164 StreamString object_fetcher_expr;
165 object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData());
166 lldb::ValueObjectSP child_sp;
167 m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp,
168 EvaluateExpressionOptions().SetKeepInMemory(true));
169 if (child_sp)
170 child_sp->SetName(ConstString(idx_name.GetData()));
171 return child_sp;
172}
173
174bool
175lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update()
176{
177 return false;
178}
179
180bool
181lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren ()
182{
183 return true;
184}
185
186size_t
187lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
188{
189 return 0;
190}
191
192lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::~NSDictionaryCodeRunningSyntheticFrontEnd ()
193{}
194
195lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
196SyntheticChildrenFrontEnd(*valobj_sp.get()),
197m_exe_ctx_ref(),
198m_ptr_size(8),
199m_data_32(NULL),
200m_data_64(NULL)
201{
202 if (valobj_sp)
203 Update();
204}
205
206lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd ()
207{
208 delete m_data_32;
209 m_data_32 = NULL;
210 delete m_data_64;
211 m_data_64 = NULL;
212}
213
214size_t
215lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
216{
217 const char* item_name = name.GetCString();
218 uint32_t idx = ExtractIndexFromString(item_name);
219 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
220 return UINT32_MAX;
221 return idx;
222}
223
224size_t
225lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren ()
226{
227 if (!m_data_32 && !m_data_64)
228 return 0;
229 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
230}
231
232bool
233lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
234{
235 m_children.clear();
236 delete m_data_32;
237 m_data_32 = NULL;
238 delete m_data_64;
239 m_data_64 = NULL;
240 m_ptr_size = 0;
241 ValueObjectSP valobj_sp = m_backend.GetSP();
242 if (!valobj_sp)
243 return false;
Enrico Granataea687532013-02-15 23:38:37 +0000244 if (!valobj_sp)
245 return false;
246 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
247 Error error;
248 if (valobj_sp->IsPointerType())
249 {
250 valobj_sp = valobj_sp->Dereference(error);
251 if (error.Fail() || !valobj_sp)
252 return false;
253 }
254 error.Clear();
255 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
256 if (!process_sp)
257 return false;
258 m_ptr_size = process_sp->GetAddressByteSize();
259 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
260 if (m_ptr_size == 4)
261 {
262 m_data_32 = new DataDescriptor_32();
263 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
264 }
265 else
266 {
267 m_data_64 = new DataDescriptor_64();
268 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
269 }
270 if (error.Fail())
271 return false;
272 m_data_ptr = data_location + m_ptr_size;
273 return false;
274}
275
276bool
277lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren ()
278{
279 return true;
280}
281
282lldb::ValueObjectSP
283lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx)
284{
285 uint32_t num_children = CalculateNumChildren();
286
287 if (idx >= num_children)
288 return lldb::ValueObjectSP();
289
290 if (m_children.empty())
291 {
292 // do the scan phase
293 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
294
295 uint32_t tries = 0;
296 uint32_t test_idx = 0;
297
298 while(tries < num_children)
299 {
300 key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size);
301 val_at_idx = key_at_idx + m_ptr_size;
302 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
303 if (!process_sp)
304 return lldb::ValueObjectSP();
305 Error error;
306 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
307 if (error.Fail())
308 return lldb::ValueObjectSP();
309 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
310 if (error.Fail())
311 return lldb::ValueObjectSP();
312
313 test_idx++;
314
315 if (!key_at_idx || !val_at_idx)
316 continue;
317 tries++;
318
319 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
320
321 m_children.push_back(descriptor);
322 }
323 }
324
325 if (idx >= m_children.size()) // should never happen
326 return lldb::ValueObjectSP();
327
328 DictionaryItemDescriptor &dict_item = m_children[idx];
329 if (!dict_item.valobj_sp)
330 {
331 // make the new ValueObject
332 StreamString expr;
333 expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = (id)%" PRIu64 " ; _lldb_valgen_item.value = (id)%" PRIu64 "; _lldb_valgen_item;",dict_item.key_ptr,dict_item.val_ptr);
334 StreamString idx_name;
335 idx_name.Printf("[%zu]",idx);
336 dict_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
337 }
338 return dict_item.valobj_sp;
339}
340
341lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
342SyntheticChildrenFrontEnd(*valobj_sp.get()),
343m_exe_ctx_ref(),
344m_ptr_size(8),
345m_data_32(NULL),
346m_data_64(NULL)
347{
348 if (valobj_sp)
349 Update ();
350}
351
352lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd ()
353{
354 delete m_data_32;
355 m_data_32 = NULL;
356 delete m_data_64;
357 m_data_64 = NULL;
358}
359
360size_t
361lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
362{
363 const char* item_name = name.GetCString();
364 uint32_t idx = ExtractIndexFromString(item_name);
365 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
366 return UINT32_MAX;
367 return idx;
368}
369
370size_t
371lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren ()
372{
373 if (!m_data_32 && !m_data_64)
374 return 0;
375 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
376}
377
378bool
379lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
380{
381 m_children.clear();
382 ValueObjectSP valobj_sp = m_backend.GetSP();
383 m_ptr_size = 0;
384 delete m_data_32;
385 m_data_32 = NULL;
386 delete m_data_64;
387 m_data_64 = NULL;
388 if (!valobj_sp)
389 return false;
Enrico Granataea687532013-02-15 23:38:37 +0000390 if (!valobj_sp)
391 return false;
392 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
393 Error error;
394 if (valobj_sp->IsPointerType())
395 {
396 valobj_sp = valobj_sp->Dereference(error);
397 if (error.Fail() || !valobj_sp)
398 return false;
399 }
400 error.Clear();
401 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
402 if (!process_sp)
403 return false;
404 m_ptr_size = process_sp->GetAddressByteSize();
405 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
406 if (m_ptr_size == 4)
407 {
408 m_data_32 = new DataDescriptor_32();
409 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
410 }
411 else
412 {
413 m_data_64 = new DataDescriptor_64();
414 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
415 }
416 if (error.Fail())
417 return false;
418 return false;
419}
420
421bool
422lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren ()
423{
424 return true;
425}
426
427lldb::ValueObjectSP
428lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
429{
430 lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
431 lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
432
433 uint32_t num_children = CalculateNumChildren();
434
435 if (idx >= num_children)
436 return lldb::ValueObjectSP();
437
438 if (m_children.empty())
439 {
440 // do the scan phase
441 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
442
443 uint32_t tries = 0;
444 uint32_t test_idx = 0;
445
446 while(tries < num_children)
447 {
448 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
449 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);;
450 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
451 if (!process_sp)
452 return lldb::ValueObjectSP();
453 Error error;
454 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
455 if (error.Fail())
456 return lldb::ValueObjectSP();
457 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
458 if (error.Fail())
459 return lldb::ValueObjectSP();
460
461 test_idx++;
462
463 if (!key_at_idx || !val_at_idx)
464 continue;
465 tries++;
466
467 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
468
469 m_children.push_back(descriptor);
470 }
471 }
472
473 if (idx >= m_children.size()) // should never happen
474 return lldb::ValueObjectSP();
475
476 DictionaryItemDescriptor &dict_item = m_children[idx];
477 if (!dict_item.valobj_sp)
478 {
479 // make the new ValueObject
480 StreamString expr;
481 expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = (id)%" PRIu64 " ; _lldb_valgen_item.value = (id)%" PRIu64 "; _lldb_valgen_item;",dict_item.key_ptr,dict_item.val_ptr);
482 StreamString idx_name;
483 idx_name.Printf("[%zu]",idx);
484 dict_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
485 }
486 return dict_item.valobj_sp;
487}
488
489template bool
490lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ;
491
492template bool
493lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ;