aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Language/ObjC/NSSet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Language/ObjC/NSSet.cpp')
-rw-r--r--lldb/source/Plugins/Language/ObjC/NSSet.cpp213
1 files changed, 192 insertions, 21 deletions
diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
index ebaa990fb74b..4dbbe6fbddff 100644
--- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
@@ -1,4 +1,4 @@
-//===-- NSSet.cpp -----------------------------------------------*- C++ -*-===//
+//===-- NSSet.cpp ---------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,12 +7,13 @@
//===----------------------------------------------------------------------===//
#include "NSSet.h"
+#include "CFBasicHash.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/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
@@ -79,6 +80,36 @@ private:
std::vector<SetItemDescriptor> m_children;
};
+class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSCFSetSyntheticFrontEnd(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 SetItemDescriptor {
+ lldb::addr_t item_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<SetItemDescriptor> m_children;
+};
+
template <typename D32, typename D64>
class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
@@ -245,21 +276,25 @@ bool lldb_private::formatters::NSSetSummaryProvider(
uint64_t value = 0;
- ConstString class_name_cs = descriptor->GetClassName();
- const char *class_name = class_name_cs.GetCString();
+ ConstString class_name(descriptor->GetClassName());
- if (!class_name || !*class_name)
+ static const ConstString g_SetI("__NSSetI");
+ static const ConstString g_OrderedSetI("__NSOrderedSetI");
+ static const ConstString g_SetM("__NSSetM");
+ static const ConstString g_SetCF("__NSCFSet");
+ static const ConstString g_SetCFRef("CFSetRef");
+
+ if (class_name.IsEmpty())
return false;
- if (!strcmp(class_name, "__NSSetI") ||
- !strcmp(class_name, "__NSOrderedSetI")) {
+ if (class_name == g_SetI || class_name == g_OrderedSetI) {
Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
return false;
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
- } else if (!strcmp(class_name, "__NSSetM")) {
+ } else if (class_name == g_SetM) {
AppleObjCRuntime *apple_runtime =
llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
Status error;
@@ -272,9 +307,15 @@ bool lldb_private::formatters::NSSetSummaryProvider(
}
if (error.Fail())
return false;
+ } else if (class_name == g_SetCF || class_name == g_SetCFRef) {
+ ExecutionContext exe_ctx(process_sp);
+ CFBasicHash cfbh;
+ if (!cfbh.Update(valobj_addr, exe_ctx))
+ return false;
+ value = cfbh.GetCount();
} else {
auto &map(NSSet_Additionals::GetAdditionalSummaries());
- auto iter = map.find(class_name_cs), end = map.end();
+ auto iter = map.find(class_name), end = map.end();
if (iter != end)
return iter->second(valobj, stream, options);
else
@@ -321,16 +362,20 @@ lldb_private::formatters::NSSetSyntheticFrontEndCreator(
if (!descriptor || !descriptor->IsValid())
return nullptr;
- ConstString class_name_cs = descriptor->GetClassName();
- const char *class_name = class_name_cs.GetCString();
+ ConstString class_name = descriptor->GetClassName();
- if (!class_name || !*class_name)
+ static const ConstString g_SetI("__NSSetI");
+ static const ConstString g_OrderedSetI("__NSOrderedSetI");
+ static const ConstString g_SetM("__NSSetM");
+ static const ConstString g_SetCF("__NSCFSet");
+ static const ConstString g_SetCFRef("CFSetRef");
+
+ if (class_name.IsEmpty())
return nullptr;
- if (!strcmp(class_name, "__NSSetI") ||
- !strcmp(class_name, "__NSOrderedSetI")) {
+ if (class_name == g_SetI || class_name == g_OrderedSetI) {
return (new NSSetISyntheticFrontEnd(valobj_sp));
- } else if (!strcmp(class_name, "__NSSetM")) {
+ } else if (class_name == g_SetM) {
AppleObjCRuntime *apple_runtime =
llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
if (apple_runtime) {
@@ -343,9 +388,11 @@ lldb_private::formatters::NSSetSyntheticFrontEndCreator(
} else {
return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
}
+ } else if (class_name == g_SetCF || class_name == g_SetCFRef) {
+ return (new NSCFSetSyntheticFrontEnd(valobj_sp));
} else {
auto &map(NSSet_Additionals::GetAdditionalSynthetics());
- auto iter = map.find(class_name_cs), end = map.end();
+ auto iter = map.find(class_name), end = map.end();
if (iter != end)
return iter->second(synth, valobj_sp);
return nullptr;
@@ -475,16 +522,18 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) {
auto ptr_size = process_sp->GetAddressByteSize();
DataBufferHeap buffer(ptr_size, 0);
switch (ptr_size) {
- case 0: // architecture has no clue?? - fail
+ case 0: // architecture has no clue - fail
return lldb::ValueObjectSP();
case 4:
- *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
+ *reinterpret_cast<uint32_t *>(buffer.GetBytes()) =
+ static_cast<uint32_t>(set_item.item_ptr);
break;
case 8:
- *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
+ *reinterpret_cast<uint64_t *>(buffer.GetBytes()) =
+ static_cast<uint64_t>(set_item.item_ptr);
break;
default:
- assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
+ lldbassert(false && "pointer size is not 4 nor 8");
}
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
@@ -501,6 +550,128 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) {
return set_item.valobj_sp;
}
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(
+ 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::NSCFSetSyntheticFrontEnd::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::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_hashtable.IsValid())
+ return 0;
+ return m_hashtable.GetCount();
+}
+
+bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::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::NSCFSetSyntheticFrontEnd::MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(
+ size_t idx) {
+ 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 val_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ // Iterate over inferior memory, reading value pointers by shifting the
+ // 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) {
+ val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
+
+ val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!val_at_idx)
+ continue;
+ tries++;
+
+ SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()};
+
+ m_children.push_back(descriptor);
+ }
+ }
+
+ if (idx >= m_children.size()) // should never happen
+ return lldb::ValueObjectSP();
+
+ SetItemDescriptor &set_item = m_children[idx];
+ if (!set_item.valobj_sp) {
+
+ DataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0));
+
+ switch (m_ptr_size) {
+ case 0: // architecture has no clue - fail
+ return lldb::ValueObjectSP();
+ case 4:
+ *reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) =
+ static_cast<uint32_t>(set_item.item_ptr);
+ break;
+ case 8:
+ *reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) =
+ static_cast<uint64_t>(set_item.item_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);
+
+ set_item.valobj_sp = CreateValueObjectFromData(
+ idx_name.GetString(), data, m_exe_ctx_ref,
+ m_backend.GetCompilerType().GetBasicTypeFromAST(
+ lldb::eBasicTypeObjCID));
+ }
+
+ return set_item.valobj_sp;
+}
+
template <typename D32, typename D64>
lldb_private::formatters::
GenericNSSetMSyntheticFrontEnd<D32, D64>::GenericNSSetMSyntheticFrontEnd(
@@ -513,7 +684,7 @@ lldb_private::formatters::
template <typename D32, typename D64>
lldb_private::formatters::
- GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd() {
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd<D32, D64>() {
delete m_data_32;
m_data_32 = nullptr;
delete m_data_64;