summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
commitcfca06d7963fa0909f90483b42a6d7d194d01e08 (patch)
tree209fb2a2d68f8f277793fc8df46c753d31bc853b /lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
parent706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff)
Notes
Diffstat (limited to 'lldb/source/Plugins/Language/ObjC/NSDictionary.cpp')
-rw-r--r--lldb/source/Plugins/Language/ObjC/NSDictionary.cpp330
1 files changed, 257 insertions, 73 deletions
diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
index ae00674c49f3..3dc07678f92f 100644
--- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -1,4 +1,4 @@
-//===-- NSDictionary.cpp ----------------------------------------*- C++ -*-===//
+//===-- NSDictionary.cpp --------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -10,14 +10,15 @@
#include "clang/AST/DeclCXX.h"
+#include "CFBasicHash.h"
#include "NSDictionary.h"
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
@@ -65,7 +66,7 @@ NSDictionary_Additionals::GetAdditionalSynthetics() {
static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
CompilerType compiler_type;
- ClangASTContext *target_ast_context = ClangASTContext::GetScratch(*target_sp);
+ TypeSystemClang *target_ast_context = TypeSystemClang::GetScratch(*target_sp);
if (target_ast_context) {
ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
@@ -76,18 +77,19 @@ static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
if (!compiler_type) {
compiler_type = target_ast_context->CreateRecordType(
- nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(),
- clang::TTK_Struct, lldb::eLanguageTypeC);
+ nullptr, OptionalClangModuleID(), lldb::eAccessPublic,
+ g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct,
+ lldb::eLanguageTypeC);
if (compiler_type) {
- ClangASTContext::StartTagDeclarationDefinition(compiler_type);
+ TypeSystemClang::StartTagDeclarationDefinition(compiler_type);
CompilerType id_compiler_type =
target_ast_context->GetBasicType(eBasicTypeObjCID);
- ClangASTContext::AddFieldToRecordType(
+ TypeSystemClang::AddFieldToRecordType(
compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
- ClangASTContext::AddFieldToRecordType(
+ TypeSystemClang::AddFieldToRecordType(
compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
- ClangASTContext::CompleteTagDeclarationDefinition(compiler_type);
+ TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
}
}
}
@@ -139,6 +141,37 @@ private:
std::vector<DictionaryItemDescriptor> m_children;
};
+class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ size_t CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+ bool Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ struct DictionaryItemDescriptor {
+ lldb::addr_t key_ptr;
+ lldb::addr_t val_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ lldb::ByteOrder m_order;
+
+ CFBasicHash m_hashtable;
+
+ CompilerType m_pair_type;
+ std::vector<DictionaryItemDescriptor> m_children;
+};
+
class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
@@ -245,64 +278,67 @@ namespace Foundation1100 {
}
namespace Foundation1428 {
- struct DataDescriptor_32 {
- uint32_t _used : 26;
- uint32_t _kvo : 1;
- uint32_t _size;
- uint32_t _buffer;
- uint64_t GetSize() { return _size; }
- };
-
- struct DataDescriptor_64 {
- uint64_t _used : 58;
- uint32_t _kvo : 1;
- uint64_t _size;
- uint64_t _buffer;
- uint64_t GetSize() { return _size; }
- };
-
-
-
+ namespace {
+ struct DataDescriptor_32 {
+ uint32_t _used : 26;
+ uint32_t _kvo : 1;
+ uint32_t _size;
+ uint32_t _buffer;
+ uint64_t GetSize() { return _size; }
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _used : 58;
+ uint32_t _kvo : 1;
+ uint64_t _size;
+ uint64_t _buffer;
+ uint64_t GetSize() { return _size; }
+ };
+ }
+
using NSDictionaryMSyntheticFrontEnd =
GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
}
namespace Foundation1437 {
- static const uint64_t NSDictionaryCapacities[] = {
- 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
- 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
- 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
- 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
- 111638519, 180634607, 292272623, 472907251
- };
-
- static const size_t NSDictionaryNumSizeBuckets = sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
-
- struct DataDescriptor_32 {
- uint32_t _buffer;
- uint32_t _muts;
- uint32_t _used : 25;
- uint32_t _kvo : 1;
- uint32_t _szidx : 6;
+ namespace {
+ static const uint64_t NSDictionaryCapacities[] = {
+ 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
+ 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
+ 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
+ 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
+ 111638519, 180634607, 292272623, 472907251
+ };
+
+ static const size_t NSDictionaryNumSizeBuckets =
+ sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
+
+ struct DataDescriptor_32 {
+ uint32_t _buffer;
+ uint32_t _muts;
+ uint32_t _used : 25;
+ uint32_t _kvo : 1;
+ uint32_t _szidx : 6;
- uint64_t GetSize() {
- return (_szidx) >= NSDictionaryNumSizeBuckets ?
- 0 : NSDictionaryCapacities[_szidx];
- }
- };
-
- struct DataDescriptor_64 {
- uint64_t _buffer;
- uint32_t _muts;
- uint32_t _used : 25;
- uint32_t _kvo : 1;
- uint32_t _szidx : 6;
+ uint64_t GetSize() {
+ return (_szidx) >= NSDictionaryNumSizeBuckets ?
+ 0 : NSDictionaryCapacities[_szidx];
+ }
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _buffer;
+ uint32_t _muts;
+ uint32_t _used : 25;
+ uint32_t _kvo : 1;
+ uint32_t _szidx : 6;
- uint64_t GetSize() {
- return (_szidx) >= NSDictionaryNumSizeBuckets ?
- 0 : NSDictionaryCapacities[_szidx];
- }
- };
+ uint64_t GetSize() {
+ return (_szidx) >= NSDictionaryNumSizeBuckets ?
+ 0 : NSDictionaryCapacities[_szidx];
+ }
+ };
+ }
using NSDictionaryMSyntheticFrontEnd =
GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
@@ -375,7 +411,9 @@ bool lldb_private::formatters::NSDictionarySummaryProvider(
static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
static const ConstString g_Dictionary0("__NSDictionary0");
- static const ConstString g_DictionaryCF("__NSCFDictionary");
+ static const ConstString g_DictionaryCF("__CFDictionary");
+ static const ConstString g_DictionaryNSCF("__NSCFDictionary");
+ static const ConstString g_DictionaryCFRef("CFDictionaryRef");
if (class_name.IsEmpty())
return false;
@@ -386,9 +424,9 @@ bool lldb_private::formatters::NSDictionarySummaryProvider(
ptr_size, 0, error);
if (error.Fail())
return false;
+
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
- } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
- class_name == g_DictionaryCF) {
+ } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) {
AppleObjCRuntime *apple_runtime =
llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
Status error;
@@ -406,8 +444,15 @@ bool lldb_private::formatters::NSDictionarySummaryProvider(
value = 1;
} else if (class_name == g_Dictionary0) {
value = 0;
- }
- else {
+ } else if (class_name == g_DictionaryCF ||
+ class_name == g_DictionaryNSCF ||
+ class_name == g_DictionaryCFRef) {
+ ExecutionContext exe_ctx(process_sp);
+ CFBasicHash cfbh;
+ if (!cfbh.Update(valobj_addr, exe_ctx))
+ return false;
+ value = cfbh.GetCount();
+ } else {
auto &map(NSDictionary_Additionals::GetAdditionalSummaries());
for (auto &candidate : map) {
if (candidate.first && candidate.first->Match(class_name))
@@ -465,6 +510,9 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
static const ConstString g_Dictionary0("__NSDictionary0");
+ static const ConstString g_DictionaryCF("__CFDictionary");
+ static const ConstString g_DictionaryNSCF("__NSCFDictionary");
+ static const ConstString g_DictionaryCFRef("CFDictionaryRef");
if (class_name.IsEmpty())
return nullptr;
@@ -483,6 +531,10 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
} else if (class_name == g_Dictionary1) {
return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_DictionaryCF ||
+ class_name == g_DictionaryNSCF ||
+ class_name == g_DictionaryCFRef) {
+ return (new NSCFDictionarySyntheticFrontEnd(valobj_sp));
} else {
auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());
for (auto &candidate : map) {
@@ -640,6 +692,140 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
return dict_item.valobj_sp;
}
+lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+ NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
+ m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {}
+
+size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ const char *item_name = name.GetCString();
+ const uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+}
+
+size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+ CalculateNumChildren() {
+ if (!m_hashtable.IsValid())
+ return 0;
+ return m_hashtable.GetCount();
+}
+
+bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref);
+}
+
+bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
+ size_t idx) {
+ lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer();
+ lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
+
+ const uint32_t num_children = CalculateNumChildren();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty()) {
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+
+ Status error;
+ lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ // Iterate over inferior memory, reading key/value pointers by shifting each
+ // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
+ // fails, otherwise, continue until the number of tries matches the number
+ // of childen.
+ while (tries < num_children) {
+ key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
+ val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
+
+ key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!key_at_idx || !val_at_idx)
+ continue;
+ tries++;
+
+ DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
+ lldb::ValueObjectSP()};
+
+ m_children.push_back(descriptor);
+ }
+ }
+
+ if (idx >= m_children.size()) // should never happen
+ return lldb::ValueObjectSP();
+
+ DictionaryItemDescriptor &dict_item = m_children[idx];
+ if (!dict_item.valobj_sp) {
+ if (!m_pair_type.IsValid()) {
+ TargetSP target_sp(m_backend.GetTargetSP());
+ if (!target_sp)
+ return ValueObjectSP();
+ m_pair_type = GetLLDBNSPairType(target_sp);
+ }
+ if (!m_pair_type.IsValid())
+ return ValueObjectSP();
+
+ DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
+
+ switch (m_ptr_size) {
+ case 0: // architecture has no clue - fail
+ return lldb::ValueObjectSP();
+ case 4: {
+ uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes());
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ } break;
+ case 8: {
+ uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes());
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ } break;
+ default:
+ lldbassert(false && "pointer size is not 4 nor 8");
+ }
+
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ DataExtractor data(buffer_sp, m_order, m_ptr_size);
+ dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+ m_exe_ctx_ref, m_pair_type);
+ }
+ return dict_item.valobj_sp;
+}
+
lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
@@ -724,7 +910,7 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
template <typename D32, typename D64>
lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
- ~GenericNSDictionaryMSyntheticFrontEnd() {
+ ~GenericNSDictionaryMSyntheticFrontEnd<D32,D64>() {
delete m_data_32;
m_data_32 = nullptr;
delete m_data_64;
@@ -732,8 +918,8 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
}
template <typename D32, typename D64>
-size_t
-lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: GetIndexOfChildWithName(ConstString name) {
+size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
+ D32, D64>::GetIndexOfChildWithName(ConstString name) {
const char *item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
@@ -782,7 +968,7 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
}
if (error.Fail())
return false;
- return false;
+ return true;
}
template <typename D32, typename D64>
@@ -794,9 +980,8 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
template <typename D32, typename D64>
lldb::ValueObjectSP
-lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
- GetChildAtIndex(
- size_t idx) {
+lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
+ D32, D64>::GetChildAtIndex(size_t idx) {
lldb::addr_t m_keys_ptr;
lldb::addr_t m_values_ptr;
if (m_data_32) {
@@ -884,7 +1069,6 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
return dict_item.valobj_sp;
}
-
lldb_private::formatters::Foundation1100::
NSDictionaryMSyntheticFrontEnd::
NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)