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/DataFormatters/CXXFormatterFunctions.h"
12 #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"
22 #include "clang/AST/DeclCXX.h"
25 using namespace lldb_private;
26 using namespace lldb_private::formatters;
29 GetLLDBNSPairType (TargetSP target_sp)
31 ClangASTType clang_type;
33 ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext();
35 if (target_ast_context)
37 ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
39 clang_type = target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(g___lldb_autogen_nspair);
43 clang_type = target_ast_context->CreateRecordType(NULL, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct, lldb::eLanguageTypeC);
47 clang_type.StartTagDeclarationDefinition();
48 ClangASTType id_clang_type = target_ast_context->GetBasicType (eBasicTypeObjCID);
49 clang_type.AddFieldToRecordType("key", id_clang_type, lldb::eAccessPublic, 0);
50 clang_type.AddFieldToRecordType("value", id_clang_type, lldb::eAccessPublic, 0);
51 clang_type.CompleteTagDeclarationDefinition();
58 namespace lldb_private {
59 namespace formatters {
60 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd
63 struct DataDescriptor_32
68 struct DataDescriptor_64
74 struct DictionaryItemDescriptor
78 lldb::ValueObjectSP valobj_sp;
82 NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
85 CalculateNumChildren ();
87 virtual lldb::ValueObjectSP
88 GetChildAtIndex (size_t idx);
97 GetIndexOfChildWithName (const ConstString &name);
100 ~NSDictionaryISyntheticFrontEnd ();
102 ExecutionContextRef m_exe_ctx_ref;
104 lldb::ByteOrder m_order;
105 DataDescriptor_32 *m_data_32;
106 DataDescriptor_64 *m_data_64;
107 lldb::addr_t m_data_ptr;
108 ClangASTType m_pair_type;
109 std::vector<DictionaryItemDescriptor> m_children;
112 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
115 struct DataDescriptor_32
124 struct DataDescriptor_64
133 struct DictionaryItemDescriptor
135 lldb::addr_t key_ptr;
136 lldb::addr_t val_ptr;
137 lldb::ValueObjectSP valobj_sp;
140 NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
143 CalculateNumChildren ();
145 virtual lldb::ValueObjectSP
146 GetChildAtIndex (size_t idx);
152 MightHaveChildren ();
155 GetIndexOfChildWithName (const ConstString &name);
158 ~NSDictionaryMSyntheticFrontEnd ();
160 ExecutionContextRef m_exe_ctx_ref;
162 lldb::ByteOrder m_order;
163 DataDescriptor_32 *m_data_32;
164 DataDescriptor_64 *m_data_64;
165 ClangASTType m_pair_type;
166 std::vector<DictionaryItemDescriptor> m_children;
169 class NSDictionaryCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
172 NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
175 CalculateNumChildren ();
177 virtual lldb::ValueObjectSP
178 GetChildAtIndex (size_t idx);
184 MightHaveChildren ();
187 GetIndexOfChildWithName (const ConstString &name);
190 ~NSDictionaryCodeRunningSyntheticFrontEnd ();
195 template<bool name_entries>
197 lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
199 ProcessSP process_sp = valobj.GetProcessSP();
203 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
208 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
210 if (!descriptor.get() || !descriptor->IsValid())
213 uint32_t ptr_size = process_sp->GetAddressByteSize();
214 bool is_64bit = (ptr_size == 8);
216 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
223 const char* class_name = descriptor->GetClassName().GetCString();
225 if (!class_name || !*class_name)
228 if (!strcmp(class_name,"__NSDictionaryI"))
231 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
234 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
236 else if (!strcmp(class_name,"__NSDictionaryM"))
239 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
242 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
244 /*else if (!strcmp(class_name,"__NSCFDictionary"))
247 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
251 value &= ~0x0f1f000000000000UL;
255 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
259 stream.Printf("%s%" PRIu64 " %s%s",
260 (name_entries ? "@\"" : ""),
262 (name_entries ? (value == 1 ? "entry" : "entries") : (value == 1 ? "key/value pair" : "key/value pairs")),
263 (name_entries ? "\"" : ""));
267 SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
270 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
273 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
277 if (!valobj_sp->IsPointerType())
280 valobj_sp = valobj_sp->AddressOf(error);
281 if (error.Fail() || !valobj_sp)
285 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
287 if (!descriptor.get() || !descriptor->IsValid())
290 const char* class_name = descriptor->GetClassName().GetCString();
292 if (!class_name || !*class_name)
295 if (!strcmp(class_name,"__NSDictionaryI"))
297 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
299 else if (!strcmp(class_name,"__NSDictionaryM"))
301 return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
305 return (new NSDictionaryCodeRunningSyntheticFrontEnd(valobj_sp));
309 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
310 SyntheticChildrenFrontEnd(*valobj_sp.get())
314 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
317 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
323 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
325 StreamString idx_name;
326 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
327 StreamString key_fetcher_expr;
328 key_fetcher_expr.Printf("(id)[(NSArray*)[(id)0x%" PRIx64 " allKeys] objectAtIndex:%" PRIu64 "]", m_backend.GetPointerValue(), (uint64_t)idx);
329 StreamString value_fetcher_expr;
330 value_fetcher_expr.Printf("(id)[(id)0x%" PRIx64 " objectForKey:(%s)]",m_backend.GetPointerValue(),key_fetcher_expr.GetData());
331 StreamString object_fetcher_expr;
332 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());
333 lldb::ValueObjectSP child_sp;
334 EvaluateExpressionOptions options;
335 options.SetKeepInMemory(true);
336 m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(),
337 GetViableFrame(m_backend.GetTargetSP().get()),
341 child_sp->SetName(ConstString(idx_name.GetData()));
346 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update()
352 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren ()
358 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
363 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::~NSDictionaryCodeRunningSyntheticFrontEnd ()
366 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
367 SyntheticChildrenFrontEnd(*valobj_sp.get()),
370 m_order(lldb::eByteOrderInvalid),
377 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd ()
386 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
388 const char* item_name = name.GetCString();
389 uint32_t idx = ExtractIndexFromString(item_name);
390 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
396 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren ()
398 if (!m_data_32 && !m_data_64)
400 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
404 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
412 ValueObjectSP valobj_sp = m_backend.GetSP();
415 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
418 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
421 m_ptr_size = process_sp->GetAddressByteSize();
422 m_order = process_sp->GetByteOrder();
423 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
426 m_data_32 = new DataDescriptor_32();
427 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
431 m_data_64 = new DataDescriptor_64();
432 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
436 m_data_ptr = data_location + m_ptr_size;
441 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren ()
447 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx)
449 uint32_t num_children = CalculateNumChildren();
451 if (idx >= num_children)
452 return lldb::ValueObjectSP();
454 if (m_children.empty())
457 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
460 uint32_t test_idx = 0;
462 while(tries < num_children)
464 key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size);
465 val_at_idx = key_at_idx + m_ptr_size;
466 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
468 return lldb::ValueObjectSP();
470 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
472 return lldb::ValueObjectSP();
473 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
475 return lldb::ValueObjectSP();
479 if (!key_at_idx || !val_at_idx)
483 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
485 m_children.push_back(descriptor);
489 if (idx >= m_children.size()) // should never happen
490 return lldb::ValueObjectSP();
492 DictionaryItemDescriptor &dict_item = m_children[idx];
493 if (!dict_item.valobj_sp)
495 if (!m_pair_type.IsValid())
497 TargetSP target_sp(m_backend.GetTargetSP());
499 return ValueObjectSP();
500 m_pair_type = GetLLDBNSPairType(target_sp);
502 if (!m_pair_type.IsValid())
503 return ValueObjectSP();
505 DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
509 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
510 *data_ptr = dict_item.key_ptr;
511 *(data_ptr+1) = dict_item.val_ptr;
515 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
516 *data_ptr = dict_item.key_ptr;
517 *(data_ptr+1) = dict_item.val_ptr;
520 StreamString idx_name;
521 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
522 DataExtractor data(buffer_sp, m_order, m_ptr_size);
523 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(),
528 return dict_item.valobj_sp;
531 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
532 SyntheticChildrenFrontEnd(*valobj_sp.get()),
535 m_order(lldb::eByteOrderInvalid),
542 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd ()
551 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
553 const char* item_name = name.GetCString();
554 uint32_t idx = ExtractIndexFromString(item_name);
555 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
561 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren ()
563 if (!m_data_32 && !m_data_64)
565 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
569 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
572 ValueObjectSP valobj_sp = m_backend.GetSP();
580 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
583 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
586 m_ptr_size = process_sp->GetAddressByteSize();
587 m_order = process_sp->GetByteOrder();
588 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
591 m_data_32 = new DataDescriptor_32();
592 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
596 m_data_64 = new DataDescriptor_64();
597 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
605 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren ()
611 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
613 lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
614 lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
616 uint32_t num_children = CalculateNumChildren();
618 if (idx >= num_children)
619 return lldb::ValueObjectSP();
621 if (m_children.empty())
624 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
627 uint32_t test_idx = 0;
629 while(tries < num_children)
631 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
632 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);;
633 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
635 return lldb::ValueObjectSP();
637 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
639 return lldb::ValueObjectSP();
640 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
642 return lldb::ValueObjectSP();
646 if (!key_at_idx || !val_at_idx)
650 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
652 m_children.push_back(descriptor);
656 if (idx >= m_children.size()) // should never happen
657 return lldb::ValueObjectSP();
659 DictionaryItemDescriptor &dict_item = m_children[idx];
660 if (!dict_item.valobj_sp)
662 if (!m_pair_type.IsValid())
664 TargetSP target_sp(m_backend.GetTargetSP());
666 return ValueObjectSP();
667 m_pair_type = GetLLDBNSPairType(target_sp);
669 if (!m_pair_type.IsValid())
670 return ValueObjectSP();
672 DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
676 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
677 *data_ptr = dict_item.key_ptr;
678 *(data_ptr+1) = dict_item.val_ptr;
682 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
683 *data_ptr = dict_item.key_ptr;
684 *(data_ptr+1) = dict_item.val_ptr;
687 StreamString idx_name;
688 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
689 DataExtractor data(buffer_sp, m_order, m_ptr_size);
690 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(),
695 return dict_item.valobj_sp;
699 lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
702 lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ;