1 //===-- NSDictionary.cpp ------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/lldb-python.h"
12 #include "lldb/DataFormatters/CXXFormatterFunctions.h"
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"
24 #include "clang/AST/DeclCXX.h"
27 using namespace lldb_private;
28 using namespace lldb_private::formatters;
31 GetLLDBNSPairType (TargetSP target_sp)
33 ClangASTType clang_type;
35 ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext();
37 if (target_ast_context)
39 ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
41 clang_type = target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(g___lldb_autogen_nspair);
45 clang_type = target_ast_context->CreateRecordType(NULL, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct, lldb::eLanguageTypeC);
49 clang_type.StartTagDeclarationDefinition();
50 ClangASTType id_clang_type = target_ast_context->GetBasicType (eBasicTypeObjCID);
51 clang_type.AddFieldToRecordType("key", id_clang_type, lldb::eAccessPublic, 0);
52 clang_type.AddFieldToRecordType("value", id_clang_type, lldb::eAccessPublic, 0);
53 clang_type.CompleteTagDeclarationDefinition();
60 namespace lldb_private {
61 namespace formatters {
62 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd
65 struct DataDescriptor_32
70 struct DataDescriptor_64
76 struct DictionaryItemDescriptor
80 lldb::ValueObjectSP valobj_sp;
84 NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
87 CalculateNumChildren ();
89 virtual lldb::ValueObjectSP
90 GetChildAtIndex (size_t idx);
99 GetIndexOfChildWithName (const ConstString &name);
102 ~NSDictionaryISyntheticFrontEnd ();
104 ExecutionContextRef m_exe_ctx_ref;
106 lldb::ByteOrder m_order;
107 DataDescriptor_32 *m_data_32;
108 DataDescriptor_64 *m_data_64;
109 lldb::addr_t m_data_ptr;
110 ClangASTType m_pair_type;
111 std::vector<DictionaryItemDescriptor> m_children;
114 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
117 struct DataDescriptor_32
126 struct DataDescriptor_64
135 struct DictionaryItemDescriptor
137 lldb::addr_t key_ptr;
138 lldb::addr_t val_ptr;
139 lldb::ValueObjectSP valobj_sp;
142 NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
145 CalculateNumChildren ();
147 virtual lldb::ValueObjectSP
148 GetChildAtIndex (size_t idx);
154 MightHaveChildren ();
157 GetIndexOfChildWithName (const ConstString &name);
160 ~NSDictionaryMSyntheticFrontEnd ();
162 ExecutionContextRef m_exe_ctx_ref;
164 lldb::ByteOrder m_order;
165 DataDescriptor_32 *m_data_32;
166 DataDescriptor_64 *m_data_64;
167 ClangASTType m_pair_type;
168 std::vector<DictionaryItemDescriptor> m_children;
171 class NSDictionaryCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
174 NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
177 CalculateNumChildren ();
179 virtual lldb::ValueObjectSP
180 GetChildAtIndex (size_t idx);
186 MightHaveChildren ();
189 GetIndexOfChildWithName (const ConstString &name);
192 ~NSDictionaryCodeRunningSyntheticFrontEnd ();
197 template<bool name_entries>
199 lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
201 ProcessSP process_sp = valobj.GetProcessSP();
205 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
210 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
212 if (!descriptor.get() || !descriptor->IsValid())
215 uint32_t ptr_size = process_sp->GetAddressByteSize();
216 bool is_64bit = (ptr_size == 8);
218 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
225 const char* class_name = descriptor->GetClassName().GetCString();
227 if (!class_name || !*class_name)
230 if (!strcmp(class_name,"__NSDictionaryI"))
233 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
236 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
238 else if (!strcmp(class_name,"__NSDictionaryM"))
241 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
244 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
246 /*else if (!strcmp(class_name,"__NSCFDictionary"))
249 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
253 value &= ~0x0f1f000000000000UL;
257 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
261 stream.Printf("%s%" PRIu64 " %s%s",
262 (name_entries ? "@\"" : ""),
264 (name_entries ? (value == 1 ? "entry" : "entries") : (value == 1 ? "key/value pair" : "key/value pairs")),
265 (name_entries ? "\"" : ""));
269 SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
272 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
275 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
279 if (!valobj_sp->IsPointerType())
282 valobj_sp = valobj_sp->AddressOf(error);
283 if (error.Fail() || !valobj_sp)
287 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
289 if (!descriptor.get() || !descriptor->IsValid())
292 const char* class_name = descriptor->GetClassName().GetCString();
294 if (!class_name || !*class_name)
297 if (!strcmp(class_name,"__NSDictionaryI"))
299 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
301 else if (!strcmp(class_name,"__NSDictionaryM"))
303 return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
307 return (new NSDictionaryCodeRunningSyntheticFrontEnd(valobj_sp));
311 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
312 SyntheticChildrenFrontEnd(*valobj_sp.get())
316 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
319 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
325 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
327 StreamString idx_name;
328 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
329 StreamString key_fetcher_expr;
330 key_fetcher_expr.Printf("(id)[(NSArray*)[(id)0x%" PRIx64 " allKeys] objectAtIndex:%" PRIu64 "]", m_backend.GetPointerValue(), (uint64_t)idx);
331 StreamString value_fetcher_expr;
332 value_fetcher_expr.Printf("(id)[(id)0x%" PRIx64 " objectForKey:(%s)]",m_backend.GetPointerValue(),key_fetcher_expr.GetData());
333 StreamString object_fetcher_expr;
334 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());
335 lldb::ValueObjectSP child_sp;
336 EvaluateExpressionOptions options;
337 options.SetKeepInMemory(true);
338 m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(),
339 GetViableFrame(m_backend.GetTargetSP().get()),
343 child_sp->SetName(ConstString(idx_name.GetData()));
348 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update()
354 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren ()
360 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
365 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::~NSDictionaryCodeRunningSyntheticFrontEnd ()
368 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
369 SyntheticChildrenFrontEnd(*valobj_sp.get()),
372 m_order(lldb::eByteOrderInvalid),
379 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd ()
388 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
390 const char* item_name = name.GetCString();
391 uint32_t idx = ExtractIndexFromString(item_name);
392 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
398 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren ()
400 if (!m_data_32 && !m_data_64)
402 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
406 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
414 ValueObjectSP valobj_sp = m_backend.GetSP();
417 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
420 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
423 m_ptr_size = process_sp->GetAddressByteSize();
424 m_order = process_sp->GetByteOrder();
425 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
428 m_data_32 = new DataDescriptor_32();
429 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
433 m_data_64 = new DataDescriptor_64();
434 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
438 m_data_ptr = data_location + m_ptr_size;
443 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren ()
449 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx)
451 uint32_t num_children = CalculateNumChildren();
453 if (idx >= num_children)
454 return lldb::ValueObjectSP();
456 if (m_children.empty())
459 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
462 uint32_t test_idx = 0;
464 while(tries < num_children)
466 key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size);
467 val_at_idx = key_at_idx + m_ptr_size;
468 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
470 return lldb::ValueObjectSP();
472 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
474 return lldb::ValueObjectSP();
475 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
477 return lldb::ValueObjectSP();
481 if (!key_at_idx || !val_at_idx)
485 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
487 m_children.push_back(descriptor);
491 if (idx >= m_children.size()) // should never happen
492 return lldb::ValueObjectSP();
494 DictionaryItemDescriptor &dict_item = m_children[idx];
495 if (!dict_item.valobj_sp)
497 if (!m_pair_type.IsValid())
499 TargetSP target_sp(m_backend.GetTargetSP());
501 return ValueObjectSP();
502 m_pair_type = GetLLDBNSPairType(target_sp);
504 if (!m_pair_type.IsValid())
505 return ValueObjectSP();
507 DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
511 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
512 *data_ptr = dict_item.key_ptr;
513 *(data_ptr+1) = dict_item.val_ptr;
517 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
518 *data_ptr = dict_item.key_ptr;
519 *(data_ptr+1) = dict_item.val_ptr;
522 StreamString idx_name;
523 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
524 DataExtractor data(buffer_sp, m_order, m_ptr_size);
525 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(),
530 return dict_item.valobj_sp;
533 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
534 SyntheticChildrenFrontEnd(*valobj_sp.get()),
537 m_order(lldb::eByteOrderInvalid),
544 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd ()
553 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
555 const char* item_name = name.GetCString();
556 uint32_t idx = ExtractIndexFromString(item_name);
557 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
563 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren ()
565 if (!m_data_32 && !m_data_64)
567 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
571 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
574 ValueObjectSP valobj_sp = m_backend.GetSP();
582 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
585 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
588 m_ptr_size = process_sp->GetAddressByteSize();
589 m_order = process_sp->GetByteOrder();
590 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
593 m_data_32 = new DataDescriptor_32();
594 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
598 m_data_64 = new DataDescriptor_64();
599 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
607 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren ()
613 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
615 lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
616 lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
618 uint32_t num_children = CalculateNumChildren();
620 if (idx >= num_children)
621 return lldb::ValueObjectSP();
623 if (m_children.empty())
626 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
629 uint32_t test_idx = 0;
631 while(tries < num_children)
633 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
634 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);;
635 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
637 return lldb::ValueObjectSP();
639 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
641 return lldb::ValueObjectSP();
642 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
644 return lldb::ValueObjectSP();
648 if (!key_at_idx || !val_at_idx)
652 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
654 m_children.push_back(descriptor);
658 if (idx >= m_children.size()) // should never happen
659 return lldb::ValueObjectSP();
661 DictionaryItemDescriptor &dict_item = m_children[idx];
662 if (!dict_item.valobj_sp)
664 if (!m_pair_type.IsValid())
666 TargetSP target_sp(m_backend.GetTargetSP());
668 return ValueObjectSP();
669 m_pair_type = GetLLDBNSPairType(target_sp);
671 if (!m_pair_type.IsValid())
672 return ValueObjectSP();
674 DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
678 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
679 *data_ptr = dict_item.key_ptr;
680 *(data_ptr+1) = dict_item.val_ptr;
684 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
685 *data_ptr = dict_item.key_ptr;
686 *(data_ptr+1) = dict_item.val_ptr;
689 StreamString idx_name;
690 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
691 DataExtractor data(buffer_sp, m_order, m_ptr_size);
692 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(),
697 return dict_item.valobj_sp;
701 lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
704 lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ;