aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/Language/ObjC
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Language/ObjC')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CF.cpp286
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CF.h32
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp114
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CFBasicHash.h76
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp1258
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.h116
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp88
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp868
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp1388
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.h93
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp215
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp206
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp321
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp831
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.h39
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.cpp370
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.h42
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCConstants.h44
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp1042
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h205
21 files changed, 7659 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CF.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CF.cpp
new file mode 100644
index 000000000000..0926192a4f38
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CF.cpp
@@ -0,0 +1,286 @@
+//===-- CF.cpp ------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CF.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ time_t epoch = GetOSXEpoch();
+ epoch = epoch + (time_t)valobj.GetValueAsSigned(0);
+ tm *tm_date = localtime(&epoch);
+ if (!tm_date)
+ return false;
+ std::string buffer(1024, 0);
+ if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
+ return false;
+ stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
+ tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
+ tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
+ return true;
+}
+
+bool lldb_private::formatters::CFBagSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ static constexpr llvm::StringLiteral g_TypeHint("CFBag");
+
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint32_t count = 0;
+
+ bool is_type_ok = false; // check to see if this is a CFBag we know about
+ if (descriptor->IsCFType()) {
+ ConstString type_name(valobj.GetTypeName());
+
+ static ConstString g_CFBag("__CFBag");
+ static ConstString g_conststruct__CFBag("const struct __CFBag");
+
+ if (type_name == g_CFBag || type_name == g_conststruct__CFBag) {
+ if (valobj.IsPointerType())
+ is_type_ok = true;
+ }
+ }
+
+ if (is_type_ok) {
+ lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;
+ Status error;
+ count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
+ if (error.Fail())
+ return false;
+ } else
+ return false;
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(options.GetLanguage()))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("\"%u value%s\"", count, (count == 1 ? "" : "s"));
+ stream << suffix;
+ return true;
+}
+
+bool lldb_private::formatters::CFBitVectorSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint32_t count = 0;
+
+ bool is_type_ok = false; // check to see if this is a CFBag we know about
+ if (descriptor->IsCFType()) {
+ ConstString type_name(valobj.GetTypeName());
+ if (type_name == "__CFMutableBitVector" || type_name == "__CFBitVector" ||
+ type_name == "CFMutableBitVectorRef" || type_name == "CFBitVectorRef") {
+ if (valobj.IsPointerType())
+ is_type_ok = true;
+ }
+ }
+
+ if (!is_type_ok)
+ return false;
+
+ Status error;
+ count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
+ addr_t data_ptr = process_sp->ReadPointerFromMemory(
+ valobj_addr + 2 * ptr_size + 2 * ptr_size, error);
+ if (error.Fail())
+ return false;
+ // make sure we do not try to read huge amounts of data
+ if (num_bytes > 1024)
+ num_bytes = 1024;
+ WritableDataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0));
+ num_bytes =
+ process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
+ if (error.Fail() || num_bytes == 0)
+ return false;
+ uint8_t *bytes = buffer_sp->GetBytes();
+ for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; byte_idx++) {
+ uint8_t byte = bytes[byte_idx];
+ bool bit0 = (byte & 1) == 1;
+ bool bit1 = (byte & 2) == 2;
+ bool bit2 = (byte & 4) == 4;
+ bool bit3 = (byte & 8) == 8;
+ bool bit4 = (byte & 16) == 16;
+ bool bit5 = (byte & 32) == 32;
+ bool bit6 = (byte & 64) == 64;
+ bool bit7 = (byte & 128) == 128;
+ stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? '1' : '0'), (bit6 ? '1' : '0'),
+ (bit5 ? '1' : '0'), (bit4 ? '1' : '0'), (bit3 ? '1' : '0'),
+ (bit2 ? '1' : '0'), (bit1 ? '1' : '0'), (bit0 ? '1' : '0'));
+ count -= 8;
+ }
+ {
+ // print the last byte ensuring we do not print spurious bits
+ uint8_t byte = bytes[num_bytes - 1];
+ bool bit0 = (byte & 1) == 1;
+ bool bit1 = (byte & 2) == 2;
+ bool bit2 = (byte & 4) == 4;
+ bool bit3 = (byte & 8) == 8;
+ bool bit4 = (byte & 16) == 16;
+ bool bit5 = (byte & 32) == 32;
+ bool bit6 = (byte & 64) == 64;
+ bool bit7 = (byte & 128) == 128;
+ if (count) {
+ stream.Printf("%c", bit7 ? '1' : '0');
+ count -= 1;
+ }
+ if (count) {
+ stream.Printf("%c", bit6 ? '1' : '0');
+ count -= 1;
+ }
+ if (count) {
+ stream.Printf("%c", bit5 ? '1' : '0');
+ count -= 1;
+ }
+ if (count) {
+ stream.Printf("%c", bit4 ? '1' : '0');
+ count -= 1;
+ }
+ if (count) {
+ stream.Printf("%c", bit3 ? '1' : '0');
+ count -= 1;
+ }
+ if (count) {
+ stream.Printf("%c", bit2 ? '1' : '0');
+ count -= 1;
+ }
+ if (count) {
+ stream.Printf("%c", bit1 ? '1' : '0');
+ count -= 1;
+ }
+ if (count)
+ stream.Printf("%c", bit0 ? '1' : '0');
+ }
+ return true;
+}
+
+bool lldb_private::formatters::CFBinaryHeapSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ static constexpr llvm::StringLiteral g_TypeHint("CFBinaryHeap");
+
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint32_t count = 0;
+
+ bool is_type_ok =
+ false; // check to see if this is a CFBinaryHeap we know about
+ if (descriptor->IsCFType()) {
+ ConstString type_name(valobj.GetTypeName());
+
+ static ConstString g_CFBinaryHeap("__CFBinaryHeap");
+ static ConstString g_conststruct__CFBinaryHeap(
+ "const struct __CFBinaryHeap");
+ static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef");
+
+ if (type_name == g_CFBinaryHeap ||
+ type_name == g_conststruct__CFBinaryHeap ||
+ type_name == g_CFBinaryHeapRef) {
+ if (valobj.IsPointerType())
+ is_type_ok = true;
+ }
+ }
+
+ if (is_type_ok) {
+ lldb::addr_t offset = 2 * ptr_size + valobj_addr;
+ Status error;
+ count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
+ if (error.Fail())
+ return false;
+ } else
+ return false;
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(options.GetLanguage()))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("\"%u item%s\"", count, (count == 1 ? "" : "s"));
+ stream << suffix;
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CF.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CF.h
new file mode 100644
index 000000000000..6165e1c235bc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CF.h
@@ -0,0 +1,32 @@
+//===-- CF.h ---------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CF_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CF_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+bool CFBagSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool CFBinaryHeapSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool CFBitVectorSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool CFAbsoluteTimeSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CF_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp
new file mode 100644
index 000000000000..42cda0146f2e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp
@@ -0,0 +1,114 @@
+#include "CFBasicHash.h"
+
+#include "lldb/Utility/Endian.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool CFBasicHash::IsValid() const {
+ if (m_address != LLDB_INVALID_ADDRESS) {
+ if (m_ptr_size == 4 && m_ht_32)
+ return true;
+ else if (m_ptr_size == 8 && m_ht_64)
+ return true;
+ else
+ return false;
+ }
+ return false;
+}
+
+bool CFBasicHash::Update(addr_t addr, ExecutionContextRef exe_ctx_rf) {
+ if (addr == LLDB_INVALID_ADDRESS || !addr)
+ return false;
+
+ m_address = addr;
+ m_exe_ctx_ref = exe_ctx_rf;
+ m_ptr_size =
+ m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetAddressByteSize();
+ m_byte_order = m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetByteOrder();
+
+ if (m_ptr_size == 4)
+ return UpdateFor(m_ht_32);
+ else if (m_ptr_size == 8)
+ return UpdateFor(m_ht_64);
+ return false;
+
+ llvm_unreachable(
+ "Unsupported architecture. Only 32bits and 64bits supported.");
+}
+
+template <typename T>
+bool CFBasicHash::UpdateFor(std::unique_ptr<__CFBasicHash<T>> &m_ht) {
+ if (m_byte_order != endian::InlHostByteOrder())
+ return false;
+
+ Status error;
+ Target *target = m_exe_ctx_ref.GetTargetSP().get();
+ addr_t addr = m_address.GetLoadAddress(target);
+ size_t size = sizeof(typename __CFBasicHash<T>::RuntimeBase) +
+ sizeof(typename __CFBasicHash<T>::Bits);
+
+ m_ht = std::make_unique<__CFBasicHash<T>>();
+ m_exe_ctx_ref.GetProcessSP()->ReadMemory(addr, m_ht.get(),
+ size, error);
+ if (error.Fail())
+ return false;
+
+ m_mutable = !(m_ht->base.cfinfoa & (1 << 6));
+ m_multi = m_ht->bits.counts_offset;
+ m_type = static_cast<HashType>(m_ht->bits.keys_offset);
+ addr_t ptr_offset = addr + size;
+ size_t ptr_count = GetPointerCount();
+ size = ptr_count * sizeof(T);
+
+ m_exe_ctx_ref.GetProcessSP()->ReadMemory(ptr_offset, m_ht->pointers, size,
+ error);
+
+ if (error.Fail()) {
+ m_ht = nullptr;
+ return false;
+ }
+
+ return true;
+}
+
+size_t CFBasicHash::GetCount() const {
+ if (!IsValid())
+ return 0;
+
+ if (!m_multi)
+ return (m_ptr_size == 4) ? m_ht_32->bits.used_buckets
+ : m_ht_64->bits.used_buckets;
+
+ // FIXME: Add support for multi
+ return 0;
+}
+
+size_t CFBasicHash::GetPointerCount() const {
+ if (!IsValid())
+ return 0;
+
+ if (m_multi)
+ return 3; // Bits::counts_offset;
+ return (m_type == HashType::dict) + 1;
+}
+
+addr_t CFBasicHash::GetKeyPointer() const {
+ if (!IsValid())
+ return LLDB_INVALID_ADDRESS;
+
+ if (m_ptr_size == 4)
+ return m_ht_32->pointers[m_ht_32->bits.keys_offset];
+
+ return m_ht_64->pointers[m_ht_64->bits.keys_offset];
+}
+
+addr_t CFBasicHash::GetValuePointer() const {
+ if (!IsValid())
+ return LLDB_INVALID_ADDRESS;
+
+ if (m_ptr_size == 4)
+ return m_ht_32->pointers[0];
+
+ return m_ht_64->pointers[0];
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CFBasicHash.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CFBasicHash.h
new file mode 100644
index 000000000000..f850c50342a3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CFBasicHash.h
@@ -0,0 +1,76 @@
+//===-- CFBasicHash.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CFBASICHASH_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CFBASICHASH_H
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+namespace lldb_private {
+
+class CFBasicHash {
+public:
+ enum class HashType { set = 0, dict };
+
+ CFBasicHash() = default;
+ ~CFBasicHash() = default;
+
+ bool Update(lldb::addr_t addr, ExecutionContextRef exe_ctx_rf);
+
+ bool IsValid() const;
+
+ bool IsMutable() const { return m_mutable; };
+ bool IsMultiVariant() const { return m_multi; }
+ HashType GetType() const { return m_type; }
+
+ size_t GetCount() const;
+ lldb::addr_t GetKeyPointer() const;
+ lldb::addr_t GetValuePointer() const;
+
+private:
+ template <typename T> struct __CFBasicHash {
+ struct RuntimeBase {
+ T cfisa;
+ T cfinfoa;
+ } base;
+
+ struct Bits {
+ uint16_t __reserved0;
+ uint16_t __reserved1 : 2;
+ uint16_t keys_offset : 1;
+ uint16_t counts_offset : 2;
+ uint16_t counts_width : 2;
+ uint16_t __reserved2 : 9;
+ uint32_t used_buckets; // number of used buckets
+ uint64_t deleted : 16; // number of elements deleted
+ uint64_t num_buckets_idx : 8; // index to number of buckets
+ uint64_t __reserved3 : 40;
+ uint64_t __reserved4;
+ } bits;
+
+ T pointers[3];
+ };
+ template <typename T> bool UpdateFor(std::unique_ptr<__CFBasicHash<T>> &m_ht);
+
+ size_t GetPointerCount() const;
+
+ uint32_t m_ptr_size = UINT32_MAX;
+ lldb::ByteOrder m_byte_order = lldb::eByteOrderInvalid;
+ Address m_address = LLDB_INVALID_ADDRESS;
+ std::unique_ptr<__CFBasicHash<uint32_t>> m_ht_32 = nullptr;
+ std::unique_ptr<__CFBasicHash<uint64_t>> m_ht_64 = nullptr;
+ ExecutionContextRef m_exe_ctx_ref;
+ bool m_mutable = true;
+ bool m_multi = false;
+ HashType m_type = HashType::set;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CFBASICHASH_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
new file mode 100644
index 000000000000..341923108e32
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
@@ -0,0 +1,1258 @@
+//===-- Cocoa.cpp ---------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Cocoa.h"
+#include "NSString.h"
+#include "ObjCConstants.h"
+
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Host/Time.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/bit.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+bool lldb_private::formatters::NSBundleSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ llvm::StringRef class_name(descriptor->GetClassName().GetCString());
+
+ if (class_name.empty())
+ return false;
+
+ if (class_name == "NSBundle") {
+ uint64_t offset = 5 * ptr_size;
+ ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
+ offset,
+ valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID),
+ true));
+
+ if (!text)
+ return false;
+
+ StreamString summary_stream;
+ bool was_nsstring_ok =
+ NSStringSummaryProvider(*text, summary_stream, options);
+ if (was_nsstring_ok && summary_stream.GetSize() > 0) {
+ stream.Printf("%s", summary_stream.GetData());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::formatters::NSTimeZoneSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ llvm::StringRef class_name(descriptor->GetClassName().GetCString());
+
+ if (class_name.empty())
+ return false;
+
+ if (class_name == "__NSTimeZone") {
+ uint64_t offset = ptr_size;
+ ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
+ offset, valobj.GetCompilerType(), true));
+
+ if (!text)
+ return false;
+
+ StreamString summary_stream;
+ bool was_nsstring_ok =
+ NSStringSummaryProvider(*text, summary_stream, options);
+ if (was_nsstring_ok && summary_stream.GetSize() > 0) {
+ stream.Printf("%s", summary_stream.GetData());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::formatters::NSNotificationSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ llvm::StringRef class_name(descriptor->GetClassName().GetCString());
+
+ if (class_name.empty())
+ return false;
+
+ if (class_name == "NSConcreteNotification") {
+ uint64_t offset = ptr_size;
+ ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
+ offset, valobj.GetCompilerType(), true));
+
+ if (!text)
+ return false;
+
+ StreamString summary_stream;
+ bool was_nsstring_ok =
+ NSStringSummaryProvider(*text, summary_stream, options);
+ if (was_nsstring_ok && summary_stream.GetSize() > 0) {
+ stream.Printf("%s", summary_stream.GetData());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::formatters::NSMachPortSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ llvm::StringRef class_name(descriptor->GetClassName().GetCString());
+
+ if (class_name.empty())
+ return false;
+
+ uint64_t port_number = 0;
+
+ if (class_name == "NSMachPort") {
+ uint64_t offset = (ptr_size == 4 ? 12 : 20);
+ Status error;
+ port_number = process_sp->ReadUnsignedIntegerFromMemory(
+ offset + valobj_addr, 4, 0, error);
+ if (error.Success()) {
+ stream.Printf("mach port: %u",
+ (uint32_t)(port_number & 0x00000000FFFFFFFF));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::formatters::NSIndexSetSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
+ ObjCLanguageRuntime::Get(*process_sp));
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ llvm::StringRef class_name(descriptor->GetClassName().GetCString());
+
+ if (class_name.empty())
+ return false;
+
+ uint64_t count = 0;
+
+ do {
+ if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") {
+ // Foundation version 2000 added a bitmask if the index set fit in 64 bits
+ // and a Tagged Pointer version if the bitmask is small enough to fit in
+ // the tagged pointer payload.
+ // It also changed the layout (but not the size) of the set descriptor.
+
+ // First check whether this is a tagged pointer. The bitmask will be in
+ // the payload of the tagged pointer.
+ uint64_t payload;
+ if (runtime->GetFoundationVersion() >= 2000
+ && descriptor->GetTaggedPointerInfo(nullptr, nullptr, &payload)) {
+ count = llvm::popcount(payload);
+ break;
+ }
+ // The first 32 bits describe the index set in all cases:
+ Status error;
+ uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + ptr_size, 4, 0, error);
+ if (error.Fail())
+ return false;
+ // Now check if the index is held in a bitmask in the object:
+ if (runtime->GetFoundationVersion() >= 2000) {
+ // The first two bits are "isSingleRange" and "isBitfield". If this is
+ // a bitfield we handle it here, otherwise set mode appropriately and
+ // the rest of the treatment is in common.
+ if ((mode & 2) == 2) {
+ // The bitfield is a 64 bit uint at the beginning of the data var.
+ uint64_t bitfield = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + 2 * ptr_size, 8, 0, error);
+ if (error.Fail())
+ return false;
+ count = llvm::popcount(bitfield);
+ break;
+ }
+ // It wasn't a bitfield, so read the isSingleRange from its new loc:
+ if ((mode & 1) == 1)
+ mode = 1; // this means the set only has one range
+ else
+ mode = 2; // this means the set has multiple ranges
+ } else {
+ // this means the set is empty - count = 0
+ if ((mode & 1) == 1) {
+ count = 0;
+ break;
+ }
+
+ if ((mode & 2) == 2)
+ mode = 1; // this means the set only has one range
+ else
+ mode = 2; // this means the set has multiple ranges
+ }
+ if (mode == 1) {
+ count = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + 3 * ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else {
+ // read a pointer to the data at 2*ptr_size
+ count = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + 2 * ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ // read the data at 2*ptr_size from the first location
+ count = process_sp->ReadUnsignedIntegerFromMemory(count + 2 * ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ }
+ } else
+ return false;
+ } while (false);
+ stream.Printf("%" PRIu64 " index%s", count, (count == 1 ? "" : "es"));
+ return true;
+}
+
+static void NSNumber_FormatChar(ValueObject &valobj, Stream &stream, char value,
+ lldb::LanguageType lang) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSNumber:char");
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(lang))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("%hhd", value);
+ stream << suffix;
+}
+
+static void NSNumber_FormatShort(ValueObject &valobj, Stream &stream,
+ short value, lldb::LanguageType lang) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSNumber:short");
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(lang))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("%hd", value);
+ stream << suffix;
+}
+
+static void NSNumber_FormatInt(ValueObject &valobj, Stream &stream, int value,
+ lldb::LanguageType lang) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSNumber:int");
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(lang))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("%d", value);
+ stream << suffix;
+}
+
+static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream,
+ int64_t value, lldb::LanguageType lang) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSNumber:long");
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(lang))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("%" PRId64 "", value);
+ stream << suffix;
+}
+
+static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream,
+ const llvm::APInt &value,
+ lldb::LanguageType lang) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSNumber:int128_t");
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(lang))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ const int radix = 10;
+ const bool isSigned = true;
+ std::string str = llvm::toString(value, radix, isSigned);
+ stream.PutCString(str.c_str());
+ stream << suffix;
+}
+
+static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream,
+ float value, lldb::LanguageType lang) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSNumber:float");
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(lang))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("%f", value);
+ stream << suffix;
+}
+
+static void NSNumber_FormatDouble(ValueObject &valobj, Stream &stream,
+ double value, lldb::LanguageType lang) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSNumber:double");
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(lang))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("%g", value);
+ stream << suffix;
+}
+
+bool lldb_private::formatters::NSNumberSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ Log *log = GetLog(LLDBLog::DataFormatters);
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ llvm::StringRef class_name(descriptor->GetClassName().GetCString());
+
+ if (class_name.empty())
+ return false;
+
+ if (class_name == "__NSCFBoolean")
+ return ObjCBooleanSummaryProvider(valobj, stream, options);
+
+ if (class_name == "NSDecimalNumber")
+ return NSDecimalNumberSummaryProvider(valobj, stream, options);
+
+ if (class_name == "NSConstantIntegerNumber") {
+ Status error;
+ int64_t value = process_sp->ReadSignedIntegerFromMemory(
+ valobj_addr + 2 * ptr_size, 8, 0, error);
+ if (error.Fail())
+ return false;
+ uint64_t encoding_addr = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ char encoding =
+ process_sp->ReadUnsignedIntegerFromMemory(encoding_addr, 1, 0, error);
+ if (error.Fail())
+ return false;
+
+ switch (encoding) {
+ case _C_CHR:
+ NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
+ return true;
+ case _C_SHT:
+ NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage());
+ return true;
+ case _C_INT:
+ NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
+ return true;
+ case _C_LNG:
+ case _C_LNG_LNG:
+ NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
+ return true;
+
+ case _C_UCHR:
+ case _C_USHT:
+ case _C_UINT:
+ case _C_ULNG:
+ case _C_ULNG_LNG:
+ stream.Printf("%" PRIu64, value);
+ return true;
+ }
+
+ return false;
+ }
+
+ if (class_name == "NSConstantFloatNumber") {
+ Status error;
+ uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + ptr_size, 4, 0, error);
+ if (error.Fail())
+ return false;
+ float flt_value = 0.0f;
+ memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int));
+ NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
+ return true;
+ }
+
+ if (class_name == "NSConstantDoubleNumber") {
+ Status error;
+ uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + ptr_size, 8, 0, error);
+ if (error.Fail())
+ return false;
+ double dbl_value = 0.0;
+ memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng));
+ NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
+ return true;
+ }
+
+ if (class_name == "NSNumber" || class_name == "__NSCFNumber") {
+ int64_t value = 0;
+ uint64_t i_bits = 0;
+ if (descriptor->GetTaggedPointerInfoSigned(&i_bits, &value)) {
+ // Check for "preserved" numbers. We still don't support them yet.
+ if (i_bits & 0x8) {
+ if (log)
+ log->Printf(
+ "Unsupported (preserved) NSNumber tagged pointer 0x%" PRIu64,
+ valobj_addr);
+ return false;
+ }
+
+ switch (i_bits) {
+ case 0:
+ NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
+ break;
+ case 1:
+ case 4:
+ NSNumber_FormatShort(valobj, stream, (short)value,
+ options.GetLanguage());
+ break;
+ case 2:
+ case 8:
+ NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
+ break;
+ case 3:
+ case 12:
+ NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
+ break;
+ default:
+ return false;
+ }
+ return true;
+ } else {
+ Status error;
+
+ AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
+ ObjCLanguageRuntime::Get(*process_sp));
+
+ const bool new_format =
+ (runtime && runtime->GetFoundationVersion() >= 1400);
+
+ enum class TypeCodes : int {
+ sint8 = 0x0,
+ sint16 = 0x1,
+ sint32 = 0x2,
+ sint64 = 0x3,
+ f32 = 0x4,
+ f64 = 0x5,
+ sint128 = 0x6
+ };
+
+ uint64_t data_location = valobj_addr + 2 * ptr_size;
+ TypeCodes type_code;
+
+ if (new_format) {
+ uint64_t cfinfoa = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + ptr_size, ptr_size, 0, error);
+
+ if (error.Fail())
+ return false;
+
+ bool is_preserved_number = cfinfoa & 0x8;
+ if (is_preserved_number) {
+ if (log)
+ log->Printf(
+ "Unsupported preserved NSNumber tagged pointer 0x%" PRIu64,
+ valobj_addr);
+ return false;
+ }
+
+ type_code = static_cast<TypeCodes>(cfinfoa & 0x7);
+ } else {
+ uint8_t data_type = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + ptr_size, 1, 0, error) &
+ 0x1F;
+
+ if (error.Fail())
+ return false;
+
+ switch (data_type) {
+ case 1:
+ type_code = TypeCodes::sint8;
+ break;
+ case 2:
+ type_code = TypeCodes::sint16;
+ break;
+ case 3:
+ type_code = TypeCodes::sint32;
+ break;
+ case 17:
+ data_location += 8;
+ [[fallthrough]];
+ case 4:
+ type_code = TypeCodes::sint64;
+ break;
+ case 5:
+ type_code = TypeCodes::f32;
+ break;
+ case 6:
+ type_code = TypeCodes::f64;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ uint64_t value = 0;
+ bool success = false;
+ switch (type_code) {
+ case TypeCodes::sint8:
+ value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0,
+ error);
+ if (error.Fail())
+ return false;
+ NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
+ success = true;
+ break;
+ case TypeCodes::sint16:
+ value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0,
+ error);
+ if (error.Fail())
+ return false;
+ NSNumber_FormatShort(valobj, stream, (short)value,
+ options.GetLanguage());
+ success = true;
+ break;
+ case TypeCodes::sint32:
+ value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0,
+ error);
+ if (error.Fail())
+ return false;
+ NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
+ success = true;
+ break;
+ case TypeCodes::sint64:
+ value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0,
+ error);
+ if (error.Fail())
+ return false;
+ NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
+ success = true;
+ break;
+ case TypeCodes::f32: {
+ uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
+ data_location, 4, 0, error);
+ if (error.Fail())
+ return false;
+ float flt_value = 0.0f;
+ memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int));
+ NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
+ success = true;
+ break;
+ }
+ case TypeCodes::f64: {
+ uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
+ data_location, 8, 0, error);
+ if (error.Fail())
+ return false;
+ double dbl_value = 0.0;
+ memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng));
+ NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
+ success = true;
+ break;
+ }
+ case TypeCodes::sint128: // internally, this is the same
+ {
+ uint64_t words[2];
+ words[1] = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8,
+ 0, error);
+ if (error.Fail())
+ return false;
+ words[0] = process_sp->ReadUnsignedIntegerFromMemory(data_location + 8,
+ 8, 0, error);
+ if (error.Fail())
+ return false;
+ llvm::APInt i128_value(128, words);
+ NSNumber_FormatInt128(valobj, stream, i128_value,
+ options.GetLanguage());
+ success = true;
+ break;
+ }
+ }
+ return success;
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::formatters::NSDecimalNumberSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ Status error;
+ int8_t exponent = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + ptr_size, 1, 0, error);
+ if (error.Fail())
+ return false;
+
+ uint8_t length_and_negative = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + ptr_size + 1, 1, 0, error);
+ if (error.Fail())
+ return false;
+
+ // Fifth bit marks negativity.
+ const bool is_negative = (length_and_negative >> 4) & 1;
+
+ // Zero length and negative means NaN.
+ uint8_t length = length_and_negative & 0xf;
+ const bool is_nan = is_negative && (length == 0);
+
+ if (is_nan) {
+ stream.Printf("NaN");
+ return true;
+ }
+
+ if (length == 0) {
+ stream.Printf("0");
+ return true;
+ }
+
+ uint64_t mantissa = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + ptr_size + 4, 8, 0, error);
+ if (error.Fail())
+ return false;
+
+ if (is_negative)
+ stream.Printf("-");
+
+ stream.Printf("%" PRIu64 " x 10^%" PRIi8, mantissa, exponent);
+ return true;
+}
+
+bool lldb_private::formatters::NSURLSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ llvm::StringRef class_name = descriptor->GetClassName().GetStringRef();
+
+ if (class_name != "NSURL")
+ return false;
+
+ uint64_t offset_text = ptr_size + ptr_size +
+ 8; // ISA + pointer + 8 bytes of data (even on 32bit)
+ uint64_t offset_base = offset_text + ptr_size;
+ CompilerType type(valobj.GetCompilerType());
+ ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
+ ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
+ if (!text || text->GetValueAsUnsigned(0) == 0)
+ return false;
+
+ StreamString base_summary;
+ if (base && base->GetValueAsUnsigned(0)) {
+ if (!NSURLSummaryProvider(*base, base_summary, options))
+ base_summary.Clear();
+ }
+ if (base_summary.Empty())
+ return NSStringSummaryProvider(*text, stream, options);
+
+ StreamString summary;
+ if (!NSStringSummaryProvider(*text, summary, options) || summary.Empty())
+ return false;
+
+ static constexpr llvm::StringLiteral quote_char("\"");
+ static constexpr llvm::StringLiteral g_TypeHint("NSString");
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(options.GetLanguage()))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ // @"A" -> @"A
+ llvm::StringRef summary_str = summary.GetString();
+ bool back_consumed =
+ summary_str.consume_back(suffix) && summary_str.consume_back(quote_char);
+ assert(back_consumed);
+ UNUSED_IF_ASSERT_DISABLED(back_consumed);
+ // @"B" -> B"
+ llvm::StringRef base_summary_str = base_summary.GetString();
+ bool front_consumed = base_summary_str.consume_front(prefix) &&
+ base_summary_str.consume_front(quote_char);
+ assert(front_consumed);
+ UNUSED_IF_ASSERT_DISABLED(front_consumed);
+ // @"A -- B"
+ if (!summary_str.empty() && !base_summary_str.empty()) {
+ stream << summary_str << " -- " << base_summary_str;
+ return true;
+ }
+
+ return false;
+}
+
+/// Bias value for tagged pointer exponents.
+/// Recommended values:
+/// 0x3e3: encodes all dates between distantPast and distantFuture
+/// except for the range within about 1e-28 second of the reference date.
+/// 0x3ef: encodes all dates for a few million years beyond distantPast and
+/// distantFuture, except within about 1e-25 second of the reference date.
+const int TAGGED_DATE_EXPONENT_BIAS = 0x3ef;
+
+struct DoubleBits {
+ uint64_t fraction : 52; // unsigned
+ uint64_t exponent : 11; // signed
+ uint64_t sign : 1;
+};
+
+struct TaggedDoubleBits {
+ uint64_t fraction : 52; // unsigned
+ uint64_t exponent : 7; // signed
+ uint64_t sign : 1;
+ uint64_t unused : 4; // placeholder for pointer tag bits
+};
+
+static uint64_t decodeExponent(uint64_t exp) {
+ // Tagged exponent field is 7-bit signed. Sign-extend the value to 64 bits
+ // before performing arithmetic.
+ return llvm::SignExtend64<7>(exp) + TAGGED_DATE_EXPONENT_BIAS;
+}
+
+static double decodeTaggedTimeInterval(uint64_t encodedTimeInterval) {
+ if (encodedTimeInterval == 0)
+ return 0.0;
+ if (encodedTimeInterval == std::numeric_limits<uint64_t>::max())
+ return (uint64_t)-0.0;
+
+ TaggedDoubleBits encodedBits =
+ llvm::bit_cast<TaggedDoubleBits>(encodedTimeInterval);
+ assert(encodedBits.unused == 0);
+
+ // Sign and fraction are represented exactly.
+ // Exponent is encoded.
+ DoubleBits decodedBits;
+ decodedBits.sign = encodedBits.sign;
+ decodedBits.fraction = encodedBits.fraction;
+ decodedBits.exponent = decodeExponent(encodedBits.exponent);
+
+ return llvm::bit_cast<double>(decodedBits);
+}
+
+bool lldb_private::formatters::NSDateSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t date_value_bits = 0;
+ double date_value = 0.0;
+
+ ConstString class_name = descriptor->GetClassName();
+
+ static const ConstString g_NSDate("NSDate");
+ static const ConstString g_dunder_NSDate("__NSDate");
+ static const ConstString g_NSTaggedDate("__NSTaggedDate");
+ static const ConstString g_NSCalendarDate("NSCalendarDate");
+ static const ConstString g_NSConstantDate("NSConstantDate");
+
+ if (class_name.IsEmpty())
+ return false;
+
+ uint64_t info_bits = 0, value_bits = 0;
+ if ((class_name == g_NSDate) || (class_name == g_dunder_NSDate) ||
+ (class_name == g_NSTaggedDate) || (class_name == g_NSConstantDate)) {
+ if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits)) {
+ date_value_bits = ((value_bits << 8) | (info_bits << 4));
+ memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
+ } else {
+ llvm::Triple triple(
+ process_sp->GetTarget().GetArchitecture().GetTriple());
+ uint32_t delta =
+ (triple.isWatchOS() && triple.isWatchABI()) ? 8 : ptr_size;
+ Status error;
+ date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + delta, 8, 0, error);
+ memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
+ if (error.Fail())
+ return false;
+ }
+ } else if (class_name == g_NSCalendarDate) {
+ Status error;
+ date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + 2 * ptr_size, 8, 0, error);
+ memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
+ if (error.Fail())
+ return false;
+ } else
+ return false;
+
+ // FIXME: It seems old dates are not formatted according to NSDate's calendar
+ // so we hardcode distantPast's value so that it looks like LLDB is doing
+ // the right thing.
+
+ // The relative time in seconds from Cocoa Epoch to [NSDate distantPast].
+ const double RelSecondsFromCocoaEpochToNSDateDistantPast = -63114076800;
+ if (date_value == RelSecondsFromCocoaEpochToNSDateDistantPast) {
+ stream.Printf("0001-01-01 00:00:00 UTC");
+ return true;
+ }
+
+ // Accomodate for the __NSTaggedDate format introduced in Foundation 1600.
+ if (class_name == g_NSTaggedDate) {
+ auto *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
+ ObjCLanguageRuntime::Get(*process_sp));
+ if (runtime && runtime->GetFoundationVersion() >= 1600)
+ date_value = decodeTaggedTimeInterval(value_bits << 4);
+ }
+
+ // this snippet of code assumes that time_t == seconds since Jan-1-1970 this
+ // is generally true and POSIXly happy, but might break if a library vendor
+ // decides to get creative
+ time_t epoch = GetOSXEpoch();
+ epoch = epoch + static_cast<time_t>(std::floor(date_value));
+ tm *tm_date = gmtime(&epoch);
+ if (!tm_date)
+ return false;
+ std::string buffer(1024, 0);
+ if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
+ return false;
+ stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
+ tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
+ tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
+ return true;
+}
+
+bool lldb_private::formatters::ObjCClassSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ ConstString class_name = descriptor->GetClassName();
+
+ if (class_name.IsEmpty())
+ return false;
+
+ if (ConstString cs = Mangled(class_name).GetDemangledName())
+ class_name = cs;
+
+ stream.Printf("%s", class_name.AsCString("<unknown class>"));
+ return true;
+}
+
+class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ ObjCClassSyntheticChildrenFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {}
+
+ ~ObjCClassSyntheticChildrenFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override { return 0; }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ return lldb::ValueObjectSP();
+ }
+
+ lldb::ChildCacheState Update() override {
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ bool MightHaveChildren() override { return false; }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ return UINT32_MAX;
+ }
+};
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::ObjCClassSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
+}
+
+template <bool needs_at>
+bool lldb_private::formatters::NSDataSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ bool is_64bit = (process_sp->GetAddressByteSize() == 8);
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t value = 0;
+
+ llvm::StringRef class_name = descriptor->GetClassName().GetCString();
+
+ if (class_name.empty())
+ return false;
+
+ bool isNSConcreteData = class_name == "NSConcreteData";
+ bool isNSConcreteMutableData = class_name == "NSConcreteMutableData";
+ bool isNSCFData = class_name == "__NSCFData";
+ if (isNSConcreteData || isNSConcreteMutableData || isNSCFData) {
+ uint32_t offset;
+ if (isNSConcreteData)
+ offset = is_64bit ? 8 : 4;
+ else
+ offset = is_64bit ? 16 : 8;
+
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == "_NSInlineData") {
+ uint32_t offset = (is_64bit ? 8 : 4);
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, 2,
+ 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == "_NSZeroData") {
+ value = 0;
+ } else
+ return false;
+
+ stream.Printf("%s%" PRIu64 " byte%s%s", (needs_at ? "@\"" : ""), value,
+ (value != 1 ? "s" : ""), (needs_at ? "\"" : ""));
+
+ return true;
+}
+
+bool lldb_private::formatters::ObjCBOOLSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();
+
+ ValueObjectSP real_guy_sp = valobj.GetSP();
+
+ if (type_info & eTypeIsPointer) {
+ Status err;
+ real_guy_sp = valobj.Dereference(err);
+ if (err.Fail() || !real_guy_sp)
+ return false;
+ } else if (type_info & eTypeIsReference) {
+ real_guy_sp = valobj.GetChildAtIndex(0);
+ if (!real_guy_sp)
+ return false;
+ }
+ int8_t value = (real_guy_sp->GetValueAsSigned(0) & 0xFF);
+ switch (value) {
+ case 0:
+ stream.Printf("NO");
+ break;
+ case 1:
+ stream.Printf("YES");
+ break;
+ default:
+ stream.Printf("%d", value);
+ break;
+ }
+ return true;
+}
+
+bool lldb_private::formatters::ObjCBooleanSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ lldb::addr_t valobj_ptr_value =
+ valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (valobj_ptr_value == LLDB_INVALID_ADDRESS)
+ return false;
+
+ ProcessSP process_sp(valobj.GetProcessSP());
+ if (!process_sp)
+ return false;
+
+ if (AppleObjCRuntime *objc_runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
+ ObjCLanguageRuntime::Get(*process_sp))) {
+ lldb::addr_t cf_true = LLDB_INVALID_ADDRESS,
+ cf_false = LLDB_INVALID_ADDRESS;
+ objc_runtime->GetValuesForGlobalCFBooleans(cf_true, cf_false);
+ if (valobj_ptr_value == cf_true) {
+ stream.PutCString("YES");
+ return true;
+ }
+ if (valobj_ptr_value == cf_false) {
+ stream.PutCString("NO");
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template <bool is_sel_ptr>
+bool lldb_private::formatters::ObjCSELSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ lldb::ValueObjectSP valobj_sp;
+
+ CompilerType charstar(valobj.GetCompilerType()
+ .GetBasicTypeFromAST(eBasicTypeChar)
+ .GetPointerType());
+
+ if (!charstar)
+ return false;
+
+ ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
+
+ if (is_sel_ptr) {
+ lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (data_address == LLDB_INVALID_ADDRESS)
+ return false;
+ valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address,
+ exe_ctx, charstar);
+ } else {
+ DataExtractor data;
+ Status error;
+ valobj.GetData(data, error);
+ if (error.Fail())
+ return false;
+ valobj_sp =
+ ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
+ }
+
+ if (!valobj_sp)
+ return false;
+
+ stream.Printf("%s", valobj_sp->GetSummaryAsCString());
+ return true;
+}
+
+// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
+// this call gives the POSIX equivalent of the Cocoa epoch
+time_t lldb_private::formatters::GetOSXEpoch() {
+ static time_t epoch = 0;
+ if (!epoch) {
+#ifndef _WIN32
+ tzset();
+ tm tm_epoch;
+ tm_epoch.tm_sec = 0;
+ tm_epoch.tm_hour = 0;
+ tm_epoch.tm_min = 0;
+ tm_epoch.tm_mon = 0;
+ tm_epoch.tm_mday = 1;
+ tm_epoch.tm_year = 2001 - 1900;
+ tm_epoch.tm_isdst = -1;
+ tm_epoch.tm_gmtoff = 0;
+ tm_epoch.tm_zone = nullptr;
+ epoch = timegm(&tm_epoch);
+#endif
+ }
+ return epoch;
+}
+
+template bool lldb_private::formatters::NSDataSummaryProvider<true>(
+ ValueObject &, Stream &, const TypeSummaryOptions &);
+
+template bool lldb_private::formatters::NSDataSummaryProvider<false>(
+ ValueObject &, Stream &, const TypeSummaryOptions &);
+
+template bool lldb_private::formatters::ObjCSELSummaryProvider<true>(
+ ValueObject &, Stream &, const TypeSummaryOptions &);
+
+template bool lldb_private::formatters::ObjCSELSummaryProvider<false>(
+ ValueObject &, Stream &, const TypeSummaryOptions &);
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.h
new file mode 100644
index 000000000000..a195d622ce58
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.h
@@ -0,0 +1,116 @@
+//===-- Cocoa.h ---------------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COCOA_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COCOA_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
+
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+
+namespace lldb_private {
+namespace formatters {
+bool NSIndexSetSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSArraySummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+template <bool needs_at>
+bool NSDataSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSNumberSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSDecimalNumberSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSNotificationSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSTimeZoneSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSMachPortSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSDateSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSBundleSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSURLSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+extern template bool NSDataSummaryProvider<true>(ValueObject &, Stream &,
+ const TypeSummaryOptions &);
+
+extern template bool NSDataSummaryProvider<false>(ValueObject &, Stream &,
+ const TypeSummaryOptions &);
+
+SyntheticChildrenFrontEnd *
+NSArraySyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+bool ObjCClassSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+SyntheticChildrenFrontEnd *
+ObjCClassSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP);
+
+bool ObjCBOOLSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool ObjCBooleanSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+template <bool is_sel_ptr>
+bool ObjCSELSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+extern template bool ObjCSELSummaryProvider<true>(ValueObject &, Stream &,
+ const TypeSummaryOptions &);
+
+extern template bool ObjCSELSummaryProvider<false>(ValueObject &, Stream &,
+ const TypeSummaryOptions &);
+
+bool NSError_SummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSException_SummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+SyntheticChildrenFrontEnd *
+NSErrorSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
+
+SyntheticChildrenFrontEnd *
+NSExceptionSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
+
+class NSArray_Additionals {
+public:
+ static std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
+ GetAdditionalSummaries();
+
+ static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
+ GetAdditionalSynthetics();
+};
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COCOA_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp
new file mode 100644
index 000000000000..1f4991bbfda2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp
@@ -0,0 +1,88 @@
+//===-- CoreMedia.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoreMedia.h"
+
+#include "lldb/Utility/Flags.h"
+#include "lldb/Utility/Log.h"
+
+#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Target/Target.h"
+#include <cinttypes>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+bool lldb_private::formatters::CMTimeSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ CompilerType type = valobj.GetCompilerType();
+ if (!type.IsValid())
+ return false;
+
+ auto type_system = type.GetTypeSystem();
+ if (!type_system)
+ return false;
+ // fetch children by offset to compensate for potential lack of debug info
+ auto int64_ty =
+ type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 64);
+ auto int32_ty =
+ type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 32);
+
+ auto value_sp(valobj.GetSyntheticChildAtOffset(0, int64_ty, true));
+ auto timescale_sp(valobj.GetSyntheticChildAtOffset(8, int32_ty, true));
+ auto flags_sp(valobj.GetSyntheticChildAtOffset(12, int32_ty, true));
+
+ if (!value_sp || !timescale_sp || !flags_sp)
+ return false;
+
+ auto value = value_sp->GetValueAsUnsigned(0);
+ auto timescale = (int32_t)timescale_sp->GetValueAsUnsigned(
+ 0); // the timescale specifies the fraction of a second each unit in the
+ // numerator occupies
+ auto flags = Flags(flags_sp->GetValueAsUnsigned(0) &
+ 0x00000000000000FF); // the flags I need sit in the LSB
+
+ const unsigned int FlagPositiveInf = 4;
+ const unsigned int FlagNegativeInf = 8;
+ const unsigned int FlagIndefinite = 16;
+
+ if (flags.AnySet(FlagIndefinite)) {
+ stream.Printf("indefinite");
+ return true;
+ }
+
+ if (flags.AnySet(FlagPositiveInf)) {
+ stream.Printf("+oo");
+ return true;
+ }
+
+ if (flags.AnySet(FlagNegativeInf)) {
+ stream.Printf("-oo");
+ return true;
+ }
+
+ switch (timescale) {
+ case 0:
+ return false;
+ case 1:
+ stream.Printf("%" PRId64 " seconds", value);
+ return true;
+ case 2:
+ stream.Printf("%" PRId64 " half seconds", value);
+ return true;
+ case 3:
+ stream.Printf("%" PRId64 " third%sof a second", value,
+ value == 1 ? " " : "s ");
+ return true;
+ default:
+ stream.Printf("%" PRId64 " %" PRId32 "th%sof a second", value, timescale,
+ value == 1 ? " " : "s ");
+ return true;
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.h
new file mode 100644
index 000000000000..7fd8560d20e1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/CoreMedia.h
@@ -0,0 +1,25 @@
+//===-- CoreMedia.h -----------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COREMEDIA_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COREMEDIA_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+
+bool CMTimeSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_COREMEDIA_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp
new file mode 100644
index 000000000000..67d0cd08f51a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp
@@ -0,0 +1,868 @@
+//===-- NSArray.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/TargetInfo.h"
+
+#include "Cocoa.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/Expression/FunctionCaller.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
+NSArray_Additionals::GetAdditionalSummaries() {
+ static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
+ return g_map;
+}
+
+std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
+NSArray_Additionals::GetAdditionalSynthetics() {
+ static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
+ g_map;
+ return g_map;
+}
+
+class NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd {
+public:
+ NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp);
+
+ ~NSArrayMSyntheticFrontEndBase() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override = 0;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+protected:
+ virtual lldb::addr_t GetDataAddress() = 0;
+
+ virtual uint64_t GetUsedCount() = 0;
+
+ virtual uint64_t GetOffset() = 0;
+
+ virtual uint64_t GetSize() = 0;
+
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size = 8;
+ CompilerType m_id_type;
+};
+
+template <typename D32, typename D64>
+class GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase {
+public:
+ GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~GenericNSArrayMSyntheticFrontEnd() override;
+
+ lldb::ChildCacheState Update() override;
+
+protected:
+ lldb::addr_t GetDataAddress() override;
+
+ uint64_t GetUsedCount() override;
+
+ uint64_t GetOffset() override;
+
+ uint64_t GetSize() override;
+
+private:
+ D32 *m_data_32;
+ D64 *m_data_64;
+};
+
+namespace Foundation1010 {
+ namespace {
+ struct DataDescriptor_32 {
+ uint32_t _used;
+ uint32_t _offset;
+ uint32_t _size : 28;
+ uint64_t _priv1 : 4;
+ uint32_t _priv2;
+ uint32_t _data;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _used;
+ uint64_t _offset;
+ uint64_t _size : 60;
+ uint64_t _priv1 : 4;
+ uint32_t _priv2;
+ uint64_t _data;
+ };
+ }
+
+ using NSArrayMSyntheticFrontEnd =
+ GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+}
+
+namespace Foundation1428 {
+ namespace {
+ struct DataDescriptor_32 {
+ uint32_t _used;
+ uint32_t _offset;
+ uint32_t _size;
+ uint32_t _data;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _used;
+ uint64_t _offset;
+ uint64_t _size;
+ uint64_t _data;
+ };
+ }
+
+ using NSArrayMSyntheticFrontEnd =
+ GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+}
+
+namespace Foundation1437 {
+ template <typename PtrType>
+ struct DataDescriptor {
+ PtrType _cow;
+ // __deque
+ PtrType _data;
+ uint32_t _offset;
+ uint32_t _size;
+ uint32_t _muts;
+ uint32_t _used;
+ };
+
+ using NSArrayMSyntheticFrontEnd =
+ GenericNSArrayMSyntheticFrontEnd<
+ DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>;
+
+ template <typename DD>
+ uint64_t
+ __NSArrayMSize_Impl(lldb_private::Process &process,
+ lldb::addr_t valobj_addr, Status &error) {
+ const lldb::addr_t start_of_descriptor =
+ valobj_addr + process.GetAddressByteSize();
+ DD descriptor = DD();
+ process.ReadMemory(start_of_descriptor, &descriptor,
+ sizeof(descriptor), error);
+ if (error.Fail()) {
+ return 0;
+ }
+ return descriptor._used;
+ }
+
+ uint64_t
+ __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
+ Status &error) {
+ if (process.GetAddressByteSize() == 4) {
+ return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr,
+ error);
+ } else {
+ return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr,
+ error);
+ }
+ }
+
+}
+
+namespace CallStackArray {
+struct DataDescriptor_32 {
+ uint32_t _data;
+ uint32_t _used;
+ uint32_t _offset;
+ const uint32_t _size = 0;
+};
+
+struct DataDescriptor_64 {
+ uint64_t _data;
+ uint64_t _used;
+ uint64_t _offset;
+ const uint64_t _size = 0;
+};
+
+using NSCallStackArraySyntheticFrontEnd =
+ GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+} // namespace CallStackArray
+
+template <typename D32, typename D64, bool Inline>
+class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~GenericNSArrayISyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size = 8;
+
+ D32 *m_data_32;
+ D64 *m_data_64;
+ CompilerType m_id_type;
+};
+
+namespace Foundation1300 {
+ struct IDD32 {
+ uint32_t used;
+ uint32_t list;
+ };
+
+ struct IDD64 {
+ uint64_t used;
+ uint64_t list;
+ };
+
+ using NSArrayISyntheticFrontEnd =
+ GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
+}
+
+namespace Foundation1430 {
+ using NSArrayISyntheticFrontEnd =
+ Foundation1428::NSArrayMSyntheticFrontEnd;
+}
+
+namespace Foundation1436 {
+ struct IDD32 {
+ uint32_t used;
+ uint32_t list; // in Inline cases, this is the first element
+ };
+
+ struct IDD64 {
+ uint64_t used;
+ uint64_t list; // in Inline cases, this is the first element
+ };
+
+ using NSArrayI_TransferSyntheticFrontEnd =
+ GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>;
+
+ using NSArrayISyntheticFrontEnd =
+ GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
+
+ using NSFrozenArrayMSyntheticFrontEnd =
+ Foundation1437::NSArrayMSyntheticFrontEnd;
+
+ uint64_t
+ __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
+ Status &error) {
+ return Foundation1437::__NSArrayMSize(process, valobj_addr, error);
+ }
+}
+
+namespace ConstantArray {
+
+struct ConstantArray32 {
+ uint64_t used;
+ uint32_t list;
+};
+
+struct ConstantArray64 {
+ uint64_t used;
+ uint64_t list;
+};
+
+using NSConstantArraySyntheticFrontEnd =
+ GenericNSArrayISyntheticFrontEnd<ConstantArray32, ConstantArray64, false>;
+} // namespace ConstantArray
+
+class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~NSArray0SyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+};
+
+class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~NSArray1SyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+};
+} // namespace formatters
+} // namespace lldb_private
+
+bool lldb_private::formatters::NSArraySummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSArray");
+
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t value = 0;
+
+ ConstString class_name(descriptor->GetClassName());
+
+ static const ConstString g_NSArrayI("__NSArrayI");
+ static const ConstString g_NSArrayM("__NSArrayM");
+ static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
+ static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
+ static const ConstString g_NSArray0("__NSArray0");
+ static const ConstString g_NSArray1("__NSSingleObjectArrayI");
+ static const ConstString g_NSArrayCF("__NSCFArray");
+ static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
+ static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
+ static const ConstString g_NSCallStackArray("_NSCallStackArray");
+ static const ConstString g_NSConstantArray("NSConstantArray");
+
+ if (class_name.IsEmpty())
+ return false;
+
+ if (class_name == g_NSArrayI) {
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSConstantArray) {
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 8,
+ 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSArrayM) {
+ AppleObjCRuntime *apple_runtime =
+ llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
+ Status error;
+ if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
+ value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error);
+ } else {
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ }
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSArrayI_Transfer) {
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSFrozenArrayM) {
+ Status error;
+ value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSArrayMLegacy) {
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSArrayMImmutable) {
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSArray0) {
+ value = 0;
+ } else if (class_name == g_NSArray1) {
+ value = 1;
+ } else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) {
+ // __NSCFArray and _NSCallStackArray store the number of elements as a
+ // pointer-sized value at offset `2 * ptr_size`.
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + 2 * ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else {
+ auto &map(NSArray_Additionals::GetAdditionalSummaries());
+ auto iter = map.find(class_name), end = map.end();
+ if (iter != end)
+ return iter->second(valobj, stream, options);
+ else
+ return false;
+ }
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(options.GetLanguage()))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");
+ stream << suffix;
+ return true;
+}
+
+lldb_private::formatters::NSArrayMSyntheticFrontEndBase::
+ NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_id_type() {
+ if (valobj_sp) {
+ TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(
+ *valobj_sp->GetExecutionContextRef().GetTargetSP());
+ if (scratch_ts_sp)
+ m_id_type = CompilerType(
+ scratch_ts_sp->weak_from_this(),
+ scratch_ts_sp->getASTContext().ObjCBuiltinIdTy.getAsOpaquePtr());
+ if (valobj_sp->GetProcessSP())
+ m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
+ }
+}
+
+template <typename D32, typename D64>
+lldb_private::formatters::
+ GenericNSArrayMSyntheticFrontEnd<D32, D64>::
+ GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr),
+ m_data_64(nullptr) {}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ NSArrayMSyntheticFrontEndBase::CalculateNumChildren() {
+ return GetUsedCount();
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(
+ uint32_t idx) {
+ if (idx >= CalculateNumChildrenIgnoringErrors())
+ return lldb::ValueObjectSP();
+ lldb::addr_t object_at_idx = GetDataAddress();
+ size_t pyhs_idx = idx;
+ pyhs_idx += GetOffset();
+ if (GetSize() <= pyhs_idx)
+ pyhs_idx -= GetSize();
+ object_at_idx += (pyhs_idx * m_ptr_size);
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
+ m_exe_ctx_ref, m_id_type);
+}
+
+template <typename D32, typename D64>
+lldb::ChildCacheState
+lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new D32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
+ error);
+ } else {
+ m_data_64 = new D64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
+ error);
+ }
+
+ return error.Success() ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+bool
+lldb_private::formatters::NSArrayMSyntheticFrontEndBase::MightHaveChildren() {
+ return true;
+}
+
+size_t
+lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName(
+ ConstString name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+template <typename D32, typename D64>
+lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::
+ GenericNSArrayMSyntheticFrontEnd::~GenericNSArrayMSyntheticFrontEnd() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+template <typename D32, typename D64>
+lldb::addr_t
+lldb_private::formatters::
+ GenericNSArrayMSyntheticFrontEnd<D32, D64>::
+ GenericNSArrayMSyntheticFrontEnd::GetDataAddress() {
+ if (!m_data_32 && !m_data_64)
+ return LLDB_INVALID_ADDRESS;
+ return m_data_32 ? m_data_32->_data : m_data_64->_data;
+}
+
+template <typename D32, typename D64>
+uint64_t
+lldb_private::formatters::
+ GenericNSArrayMSyntheticFrontEnd<D32, D64>::
+ GenericNSArrayMSyntheticFrontEnd::GetUsedCount() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->_used : m_data_64->_used;
+}
+
+template <typename D32, typename D64>
+uint64_t
+lldb_private::formatters::
+ GenericNSArrayMSyntheticFrontEnd<D32, D64>::
+ GenericNSArrayMSyntheticFrontEnd::GetOffset() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->_offset : m_data_64->_offset;
+}
+
+template <typename D32, typename D64>
+uint64_t
+lldb_private::formatters::
+ GenericNSArrayMSyntheticFrontEnd<D32, D64>::
+ GenericNSArrayMSyntheticFrontEnd::GetSize() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->_size : m_data_64->_size;
+}
+
+template <typename D32, typename D64, bool Inline>
+lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
+ GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
+ m_data_32(nullptr), m_data_64(nullptr) {
+ if (valobj_sp) {
+ CompilerType type = valobj_sp->GetCompilerType();
+ if (type) {
+ TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(
+ *valobj_sp->GetExecutionContextRef().GetTargetSP());
+ if (scratch_ts_sp)
+ m_id_type = scratch_ts_sp->GetType(
+ scratch_ts_sp->getASTContext().ObjCBuiltinIdTy);
+ }
+ }
+}
+
+template <typename D32, typename D64, bool Inline>
+lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
+ GenericNSArrayISyntheticFrontEnd::~GenericNSArrayISyntheticFrontEnd() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+template <typename D32, typename D64, bool Inline>
+size_t
+lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
+ GetIndexOfChildWithName(ConstString name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+template <typename D32, typename D64, bool Inline>
+llvm::Expected<uint32_t>
+lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<
+ D32, D64, Inline>::CalculateNumChildren() {
+ return m_data_32 ? m_data_32->used : m_data_64->used;
+}
+
+template <typename D32, typename D64, bool Inline>
+lldb::ChildCacheState
+lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64,
+ Inline>::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new D32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
+ error);
+ } else {
+ m_data_64 = new D64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
+ error);
+ }
+
+ return error.Success() ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+template <typename D32, typename D64, bool Inline>
+bool
+lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
+ MightHaveChildren() {
+ return true;
+}
+
+template <typename D32, typename D64, bool Inline>
+lldb::ValueObjectSP
+lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
+ GetChildAtIndex(uint32_t idx) {
+ if (idx >= CalculateNumChildrenIgnoringErrors())
+ return lldb::ValueObjectSP();
+ lldb::addr_t object_at_idx;
+ if (Inline) {
+ object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size;
+ object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header
+ object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer
+ } else {
+ object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
+ }
+ object_at_idx += (idx * m_ptr_size);
+
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
+ m_exe_ctx_ref, m_id_type);
+}
+
+lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {}
+
+size_t
+lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ return UINT32_MAX;
+}
+
+llvm::Expected<uint32_t>
+lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {
+ return 0;
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {
+ return false;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ return lldb::ValueObjectSP();
+}
+
+lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}
+
+size_t
+lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ static const ConstString g_zero("[0]");
+
+ if (name == g_zero)
+ return 0;
+
+ return UINT32_MAX;
+}
+
+llvm::Expected<uint32_t>
+lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {
+ return 1;
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ static const ConstString g_zero("[0]");
+
+ if (idx == 0) {
+ TypeSystemClangSP scratch_ts_sp =
+ ScratchTypeSystemClang::GetForTarget(*m_backend.GetTargetSP());
+ if (scratch_ts_sp) {
+ CompilerType id_type(scratch_ts_sp->GetBasicType(lldb::eBasicTypeObjCID));
+ return m_backend.GetSyntheticChildAtOffset(
+ m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true,
+ g_zero);
+ }
+ }
+ return lldb::ValueObjectSP();
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::NSArraySyntheticFrontEndCreator(
+ CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return nullptr;
+ AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
+ ObjCLanguageRuntime::Get(*process_sp));
+ if (!runtime)
+ return nullptr;
+
+ CompilerType valobj_type(valobj_sp->GetCompilerType());
+ Flags flags(valobj_type.GetTypeInfo());
+
+ if (flags.IsClear(eTypeIsPointer)) {
+ Status error;
+ valobj_sp = valobj_sp->AddressOf(error);
+ if (error.Fail() || !valobj_sp)
+ return nullptr;
+ }
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(*valobj_sp));
+
+ if (!descriptor || !descriptor->IsValid())
+ return nullptr;
+
+ ConstString class_name(descriptor->GetClassName());
+
+ static const ConstString g_NSArrayI("__NSArrayI");
+ static const ConstString g_NSConstantArray("NSConstantArray");
+ static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
+ static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
+ static const ConstString g_NSArrayM("__NSArrayM");
+ static const ConstString g_NSArray0("__NSArray0");
+ static const ConstString g_NSArray1("__NSSingleObjectArrayI");
+ static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
+ static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
+ static const ConstString g_NSCallStackArray("_NSCallStackArray");
+
+ if (class_name.IsEmpty())
+ return nullptr;
+
+ if (class_name == g_NSArrayI) {
+ if (runtime->GetFoundationVersion() >= 1436)
+ return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp));
+ if (runtime->GetFoundationVersion() >= 1430)
+ return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp));
+ return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_NSArrayI_Transfer) {
+ return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_NSConstantArray) {
+ return new ConstantArray::NSConstantArraySyntheticFrontEnd(valobj_sp);
+ } else if (class_name == g_NSFrozenArrayM) {
+ return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_NSArray0) {
+ return (new NSArray0SyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_NSArray1) {
+ return (new NSArray1SyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_NSArrayM) {
+ if (runtime->GetFoundationVersion() >= 1437)
+ return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp));
+ if (runtime->GetFoundationVersion() >= 1428)
+ return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp));
+ if (runtime->GetFoundationVersion() >= 1100)
+ return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_NSCallStackArray) {
+ return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp));
+ } else {
+ auto &map(NSArray_Additionals::GetAdditionalSynthetics());
+ auto iter = map.find(class_name), end = map.end();
+ if (iter != end)
+ return iter->second(synth, valobj_sp);
+ }
+
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
new file mode 100644
index 000000000000..ec6fd756394a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -0,0 +1,1388 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <mutex>
+
+#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/Target/Language.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
+ ConstString p)
+ : m_prefix(p) {}
+
+bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match(
+ ConstString class_name) {
+ return class_name.GetStringRef().starts_with(m_prefix.GetStringRef());
+}
+
+NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n)
+ : m_name(n) {}
+
+bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match(
+ ConstString class_name) {
+ return (class_name == m_name);
+}
+
+NSDictionary_Additionals::AdditionalFormatters<
+ CXXFunctionSummaryFormat::Callback> &
+NSDictionary_Additionals::GetAdditionalSummaries() {
+ static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map;
+ return g_map;
+}
+
+NSDictionary_Additionals::AdditionalFormatters<
+ CXXSyntheticChildren::CreateFrontEndCallback> &
+NSDictionary_Additionals::GetAdditionalSynthetics() {
+ static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback>
+ g_map;
+ return g_map;
+}
+
+static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
+ CompilerType compiler_type;
+ TypeSystemClangSP scratch_ts_sp =
+ ScratchTypeSystemClang::GetForTarget(*target_sp);
+
+ if (!scratch_ts_sp)
+ return compiler_type;
+
+ static constexpr llvm::StringLiteral g_lldb_autogen_nspair("__lldb_autogen_nspair");
+
+ compiler_type = scratch_ts_sp->GetTypeForIdentifier<clang::CXXRecordDecl>(g_lldb_autogen_nspair);
+
+ if (!compiler_type) {
+ compiler_type = scratch_ts_sp->CreateRecordType(
+ nullptr, OptionalClangModuleID(), lldb::eAccessPublic,
+ g_lldb_autogen_nspair, llvm::to_underlying(clang::TagTypeKind::Struct),
+ lldb::eLanguageTypeC);
+
+ if (compiler_type) {
+ TypeSystemClang::StartTagDeclarationDefinition(compiler_type);
+ CompilerType id_compiler_type =
+ scratch_ts_sp->GetBasicType(eBasicTypeObjCID);
+ TypeSystemClang::AddFieldToRecordType(
+ compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
+ TypeSystemClang::AddFieldToRecordType(
+ compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
+ TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
+ }
+ }
+ return compiler_type;
+}
+
+namespace lldb_private {
+namespace formatters {
+class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~NSDictionaryISyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ struct DataDescriptor_32 {
+ uint32_t _used : 26;
+ uint32_t _szidx : 6;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _used : 58;
+ uint32_t _szidx : 6;
+ };
+
+ 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 = 8;
+ lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
+ DataDescriptor_32 *m_data_32 = nullptr;
+ DataDescriptor_64 *m_data_64 = nullptr;
+ lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;
+ CompilerType m_pair_type;
+ std::vector<DictionaryItemDescriptor> m_children;
+};
+
+class NSConstantDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ ExecutionContextRef m_exe_ctx_ref;
+ CompilerType m_pair_type;
+ uint8_t m_ptr_size = 8;
+ lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
+ unsigned int m_size = 0;
+ lldb::addr_t m_keys_ptr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t m_objects_ptr = LLDB_INVALID_ADDRESS;
+
+ struct DictionaryItemDescriptor {
+ lldb::addr_t key_ptr;
+ lldb::addr_t val_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+
+ std::vector<DictionaryItemDescriptor> m_children;
+};
+
+class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState 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 = 8;
+ lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
+
+ CFBasicHash m_hashtable;
+
+ CompilerType m_pair_type;
+ std::vector<DictionaryItemDescriptor> m_children;
+};
+
+class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~NSDictionary1SyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ ValueObjectSP m_pair;
+};
+
+template <typename D32, typename D64>
+class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~GenericNSDictionaryMSyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState 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 = 8;
+ lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
+ D32 *m_data_32;
+ D64 *m_data_64;
+ CompilerType m_pair_type;
+ std::vector<DictionaryItemDescriptor> m_children;
+};
+
+namespace Foundation1100 {
+ class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+ public:
+ NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~NSDictionaryMSyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+ private:
+ struct DataDescriptor_32 {
+ uint32_t _used : 26;
+ uint32_t _kvo : 1;
+ uint32_t _size;
+ uint32_t _mutations;
+ uint32_t _objs_addr;
+ uint32_t _keys_addr;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _used : 58;
+ uint32_t _kvo : 1;
+ uint64_t _size;
+ uint64_t _mutations;
+ uint64_t _objs_addr;
+ uint64_t _keys_addr;
+ };
+
+ 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 = 8;
+ lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
+ DataDescriptor_32 *m_data_32 = nullptr;
+ DataDescriptor_64 *m_data_64 = nullptr;
+ CompilerType m_pair_type;
+ std::vector<DictionaryItemDescriptor> m_children;
+ };
+}
+
+namespace Foundation1428 {
+ 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);
+
+ namespace {
+ 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];
+ }
+ };
+ } // namespace
+
+ using NSDictionaryMSyntheticFrontEnd =
+ GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+
+ template <typename DD>
+ uint64_t
+ __NSDictionaryMSize_Impl(lldb_private::Process &process,
+ lldb::addr_t valobj_addr, Status &error) {
+ const lldb::addr_t start_of_descriptor =
+ valobj_addr + process.GetAddressByteSize();
+ DD descriptor = DD();
+ process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
+ error);
+ if (error.Fail()) {
+ return 0;
+ }
+ return descriptor._used;
+ }
+
+ uint64_t
+ __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
+ Status &error) {
+ if (process.GetAddressByteSize() == 4) {
+ return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
+ error);
+ } else {
+ return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
+ error);
+ }
+ }
+
+}
+} // namespace formatters
+} // namespace lldb_private
+
+template <bool name_entries>
+bool lldb_private::formatters::NSDictionarySummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSDictionary");
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetNonKVOClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+ bool is_64bit = (ptr_size == 8);
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t value = 0;
+
+ ConstString class_name(descriptor->GetClassName());
+
+ static const ConstString g_DictionaryI("__NSDictionaryI");
+ static const ConstString g_DictionaryM("__NSDictionaryM");
+ static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
+ static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
+ static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");
+ static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
+ static const ConstString g_Dictionary0("__NSDictionary0");
+ static const ConstString g_DictionaryCF("__CFDictionary");
+ static const ConstString g_DictionaryNSCF("__NSCFDictionary");
+ static const ConstString g_DictionaryCFRef("CFDictionaryRef");
+ static const ConstString g_ConstantDictionary("NSConstantDictionary");
+
+ if (class_name.IsEmpty())
+ return false;
+
+ if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
+ 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 (class_name == g_ConstantDictionary) {
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + 2 * ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
+ class_name == g_DictionaryMFrozen) {
+ AppleObjCRuntime *apple_runtime =
+ llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
+ Status error;
+ if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
+ value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
+ error);
+ } else {
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
+ }
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_Dictionary1) {
+ value = 1;
+ } else if (class_name == g_Dictionary0) {
+ value = 0;
+ } 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))
+ return candidate.second(valobj, stream, options);
+ }
+ return false;
+ }
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(options.GetLanguage()))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("%" PRIu64 " %s%s", value, "key/value pair",
+ value == 1 ? "" : "s");
+ stream << suffix;
+ return true;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
+ CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return nullptr;
+ AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
+ ObjCLanguageRuntime::Get(*process_sp));
+ if (!runtime)
+ return nullptr;
+
+ CompilerType valobj_type(valobj_sp->GetCompilerType());
+ Flags flags(valobj_type.GetTypeInfo());
+
+ if (flags.IsClear(eTypeIsPointer)) {
+ Status error;
+ valobj_sp = valobj_sp->AddressOf(error);
+ if (error.Fail() || !valobj_sp)
+ return nullptr;
+ }
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(*valobj_sp));
+
+ if (!descriptor || !descriptor->IsValid())
+ return nullptr;
+
+ ConstString class_name(descriptor->GetClassName());
+
+ static const ConstString g_DictionaryI("__NSDictionaryI");
+ static const ConstString g_DictionaryM("__NSDictionaryM");
+ static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
+ static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
+ static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");
+ 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");
+ static const ConstString g_ConstantDictionary("NSConstantDictionary");
+
+ if (class_name.IsEmpty())
+ return nullptr;
+
+ if (class_name == g_DictionaryI) {
+ return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_ConstantDictionary) {
+ return (new NSConstantDictionarySyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) {
+ if (runtime->GetFoundationVersion() >= 1437) {
+ return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
+ } else if (runtime->GetFoundationVersion() >= 1428) {
+ return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));
+ } else {
+ return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
+ }
+ } else if (class_name == g_DictionaryMLegacy) {
+ 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) {
+ if (candidate.first && candidate.first->Match((class_name)))
+ return candidate.second(synth, valobj_sp);
+ }
+ }
+
+ return nullptr;
+}
+
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
+ NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
+
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
+ ~NSDictionaryISyntheticFrontEnd() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ NSDictionaryISyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
+ m_children.clear();
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ m_ptr_size = 0;
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ error);
+ } else {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ error);
+ }
+ if (error.Fail())
+ return lldb::ChildCacheState::eRefetch;
+ m_data_ptr = data_location + m_ptr_size;
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ uint32_t num_children = CalculateNumChildrenIgnoringErrors();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty()) {
+ // do the scan phase
+ lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ while (tries < num_children) {
+ key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
+ val_at_idx = key_at_idx + m_ptr_size;
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
+ 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();
+
+ WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
+
+ if (m_ptr_size == 8) {
+ uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ } else {
+ uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ }
+
+ 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::NSCFDictionarySyntheticFrontEnd::
+ NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), 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 >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ NSCFDictionarySyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_hashtable.IsValid())
+ return 0;
+ return m_hashtable.GetCount();
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)
+ ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
+ uint32_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 = CalculateNumChildrenIgnoringErrors();
+
+ 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();
+
+ WritableDataBufferSP 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::NSConstantDictionarySyntheticFrontEnd::
+ NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {}
+
+size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ NSConstantDictionarySyntheticFrontEnd::CalculateNumChildren() {
+ return m_size;
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0);
+ m_size = process_sp->ReadUnsignedIntegerFromMemory(
+ valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error);
+ if (error.Fail())
+ return lldb::ChildCacheState::eRefetch;
+ m_keys_ptr =
+ process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size, error);
+ if (error.Fail())
+ return lldb::ChildCacheState::eRefetch;
+ m_objects_ptr =
+ process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size, error);
+
+ return error.Success() ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP lldb_private::formatters::
+ NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ uint32_t num_children = CalculateNumChildrenIgnoringErrors();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty()) {
+ // do the scan phase
+ lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+
+ for (unsigned int child = 0; child < num_children; ++child) {
+ Status error;
+ key_at_idx = process_sp->ReadPointerFromMemory(
+ m_keys_ptr + child * m_ptr_size, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ val_at_idx = process_sp->ReadPointerFromMemory(
+ m_objects_ptr + child * m_ptr_size, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ 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();
+
+ WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
+
+ if (m_ptr_size == 8) {
+ uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ } else {
+ uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ }
+
+ 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) {}
+
+size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ static const ConstString g_zero("[0]");
+ return name == g_zero ? 0 : UINT32_MAX;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ NSDictionary1SyntheticFrontEnd::CalculateNumChildren() {
+ return 1;
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() {
+ m_pair.reset();
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (idx != 0)
+ return lldb::ValueObjectSP();
+
+ if (m_pair.get())
+ return m_pair;
+
+ auto process_sp(m_backend.GetProcessSP());
+ if (!process_sp)
+ return nullptr;
+
+ auto ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t key_ptr =
+ m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
+ lldb::addr_t value_ptr = key_ptr + ptr_size;
+
+ Status error;
+
+ lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
+ if (error.Fail())
+ return nullptr;
+ lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
+ if (error.Fail())
+ return nullptr;
+
+ auto pair_type =
+ GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
+
+ WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
+
+ if (ptr_size == 8) {
+ uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+ *data_ptr = key_at_idx;
+ *(data_ptr + 1) = value_at_idx;
+ } else {
+ uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+ *data_ptr = key_at_idx;
+ *(data_ptr + 1) = value_at_idx;
+ }
+
+ DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
+ m_pair = CreateValueObjectFromData(
+ "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
+
+ return m_pair;
+}
+
+template <typename D32, typename D64>
+lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32, D64>::
+ GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
+ m_data_32(nullptr), m_data_64(nullptr), m_pair_type() {}
+
+template <typename D32, typename D64>
+lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
+ D32, D64>::GenericNSDictionaryMSyntheticFrontEnd::
+ ~GenericNSDictionaryMSyntheticFrontEnd() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+template <typename D32, typename D64>
+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 >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+template <typename D32, typename D64>
+llvm::Expected<uint32_t>
+lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
+ D32, D64>::CalculateNumChildren() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);
+}
+
+template <typename D32, typename D64>
+lldb::ChildCacheState
+lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,
+ D64>::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new D32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
+ error);
+ } else {
+ m_data_64 = new D64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
+ error);
+ }
+
+ return error.Success() ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+template <typename D32, typename D64>
+bool
+lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
+ MightHaveChildren() {
+ return true;
+}
+
+template <typename D32, typename D64>
+lldb::ValueObjectSP
+lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
+ D32, D64>::GetChildAtIndex(uint32_t idx) {
+ lldb::addr_t m_keys_ptr;
+ lldb::addr_t m_values_ptr;
+ if (m_data_32) {
+ uint32_t size = m_data_32->GetSize();
+ m_keys_ptr = m_data_32->_buffer;
+ m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
+ } else {
+ uint32_t size = m_data_64->GetSize();
+ m_keys_ptr = m_data_64->_buffer;
+ m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
+ }
+
+ uint32_t num_children = CalculateNumChildrenIgnoringErrors();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty()) {
+ // do the scan phase
+ lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ 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);
+ ;
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
+ 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();
+
+ WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
+
+ if (m_ptr_size == 8) {
+ uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ } else {
+ uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ }
+
+ 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::Foundation1100::NSDictionaryMSyntheticFrontEnd::
+ NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
+
+lldb_private::formatters::Foundation1100::
+ NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+size_t
+lldb_private::formatters::Foundation1100::
+ NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::Foundation1100::
+ NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+}
+
+lldb::ChildCacheState lldb_private::formatters::Foundation1100::
+ NSDictionaryMSyntheticFrontEnd::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ error);
+ } else {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ error);
+ }
+
+ return error.Success() ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+bool
+lldb_private::formatters::Foundation1100::
+ NSDictionaryMSyntheticFrontEnd::MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::Foundation1100::
+ NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ lldb::addr_t m_keys_ptr =
+ (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
+ lldb::addr_t m_values_ptr =
+ (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
+
+ uint32_t num_children = CalculateNumChildrenIgnoringErrors();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty()) {
+ // do the scan phase
+ lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ 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);
+ ;
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
+ 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();
+
+ WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
+
+ if (m_ptr_size == 8) {
+ uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ } else {
+ uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ }
+
+ 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;
+}
+
+template bool lldb_private::formatters::NSDictionarySummaryProvider<true>(
+ ValueObject &, Stream &, const TypeSummaryOptions &);
+
+template bool lldb_private::formatters::NSDictionarySummaryProvider<false>(
+ ValueObject &, Stream &, const TypeSummaryOptions &);
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.h
new file mode 100644
index 000000000000..57dacd6759d2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.h
@@ -0,0 +1,93 @@
+//===-- NSDictionary.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSDICTIONARY_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSDICTIONARY_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
+
+#include <map>
+#include <memory>
+
+namespace lldb_private {
+namespace formatters {
+template <bool name_entries>
+bool NSDictionarySummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+extern template bool
+NSDictionarySummaryProvider<true>(ValueObject &, Stream &,
+ const TypeSummaryOptions &);
+
+extern template bool
+NSDictionarySummaryProvider<false>(ValueObject &, Stream &,
+ const TypeSummaryOptions &);
+
+SyntheticChildrenFrontEnd *
+NSDictionarySyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+class NSDictionary_Additionals {
+public:
+ class AdditionalFormatterMatching {
+ public:
+ class Matcher {
+ public:
+ virtual ~Matcher() = default;
+ virtual bool Match(ConstString class_name) = 0;
+
+ typedef std::unique_ptr<Matcher> UP;
+ };
+ class Prefix : public Matcher {
+ public:
+ Prefix(ConstString p);
+ ~Prefix() override = default;
+ bool Match(ConstString class_name) override;
+
+ private:
+ ConstString m_prefix;
+ };
+ class Full : public Matcher {
+ public:
+ Full(ConstString n);
+ ~Full() override = default;
+ bool Match(ConstString class_name) override;
+
+ private:
+ ConstString m_name;
+ };
+ typedef Matcher::UP MatcherUP;
+
+ MatcherUP GetFullMatch(ConstString n) { return std::make_unique<Full>(n); }
+
+ MatcherUP GetPrefixMatch(ConstString p) {
+ return std::make_unique<Prefix>(p);
+ }
+ };
+
+ template <typename FormatterType>
+ using AdditionalFormatter =
+ std::pair<AdditionalFormatterMatching::MatcherUP, FormatterType>;
+
+ template <typename FormatterType>
+ using AdditionalFormatters = std::vector<AdditionalFormatter<FormatterType>>;
+
+ static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> &
+ GetAdditionalSummaries();
+
+ static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback> &
+ GetAdditionalSynthetics();
+};
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSDICTIONARY_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp
new file mode 100644
index 000000000000..5ef7edc7e80c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp
@@ -0,0 +1,215 @@
+//===-- NSError.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+
+#include "Cocoa.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+#include "Plugins/Language/ObjC/NSString.h"
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+static lldb::addr_t DerefToNSErrorPointer(ValueObject &valobj) {
+ CompilerType valobj_type(valobj.GetCompilerType());
+ Flags type_flags(valobj_type.GetTypeInfo());
+ if (type_flags.AllClear(eTypeHasValue)) {
+ if (valobj.IsBaseClass() && valobj.GetParent())
+ return valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ } else {
+ lldb::addr_t ptr_value = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (type_flags.AllSet(eTypeIsPointer)) {
+ CompilerType pointee_type(valobj_type.GetPointeeType());
+ Flags pointee_flags(pointee_type.GetTypeInfo());
+ if (pointee_flags.AllSet(eTypeIsPointer)) {
+ if (ProcessSP process_sp = valobj.GetProcessSP()) {
+ Status error;
+ ptr_value = process_sp->ReadPointerFromMemory(ptr_value, error);
+ }
+ }
+ }
+ return ptr_value;
+ }
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool lldb_private::formatters::NSError_SummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ProcessSP process_sp(valobj.GetProcessSP());
+ if (!process_sp)
+ return false;
+
+ lldb::addr_t ptr_value = DerefToNSErrorPointer(valobj);
+ if (ptr_value == LLDB_INVALID_ADDRESS)
+ return false;
+
+ size_t ptr_size = process_sp->GetAddressByteSize();
+ lldb::addr_t code_location = ptr_value + 2 * ptr_size;
+ lldb::addr_t domain_location = ptr_value + 3 * ptr_size;
+
+ Status error;
+ uint64_t code = process_sp->ReadUnsignedIntegerFromMemory(code_location,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+
+ lldb::addr_t domain_str_value =
+ process_sp->ReadPointerFromMemory(domain_location, error);
+ if (error.Fail() || domain_str_value == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (!domain_str_value) {
+ stream.Printf("domain: nil - code: %" PRIu64, code);
+ return true;
+ }
+
+ InferiorSizedWord isw(domain_str_value, *process_sp);
+ TypeSystemClangSP scratch_ts_sp =
+ ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget());
+
+ if (!scratch_ts_sp)
+ return false;
+ ValueObjectSP domain_str_sp = ValueObject::CreateValueObjectFromData(
+ "domain_str", isw.GetAsData(process_sp->GetByteOrder()),
+ valobj.GetExecutionContextRef(),
+ scratch_ts_sp->GetBasicType(lldb::eBasicTypeVoid).GetPointerType());
+
+ if (!domain_str_sp)
+ return false;
+
+ StreamString domain_str_summary;
+ if (NSStringSummaryProvider(*domain_str_sp, domain_str_summary, options) &&
+ !domain_str_summary.Empty()) {
+ stream.Printf("domain: %s - code: %" PRIu64, domain_str_summary.GetData(),
+ code);
+ return true;
+ } else {
+ stream.Printf("domain: nil - code: %" PRIu64, code);
+ return true;
+ }
+}
+
+class NSErrorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSErrorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {}
+
+ ~NSErrorSyntheticFrontEnd() override = default;
+ // no need to delete m_child_ptr - it's kept alive by the cluster manager on
+ // our behalf
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ if (m_child_ptr)
+ return 1;
+ if (m_child_sp)
+ return 1;
+ return 0;
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ if (idx != 0)
+ return lldb::ValueObjectSP();
+
+ if (m_child_ptr)
+ return m_child_ptr->GetSP();
+ return m_child_sp;
+ }
+
+ lldb::ChildCacheState Update() override {
+ m_child_ptr = nullptr;
+ m_child_sp.reset();
+
+ ProcessSP process_sp(m_backend.GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ lldb::addr_t userinfo_location = DerefToNSErrorPointer(m_backend);
+ if (userinfo_location == LLDB_INVALID_ADDRESS)
+ return lldb::ChildCacheState::eRefetch;
+
+ size_t ptr_size = process_sp->GetAddressByteSize();
+
+ userinfo_location += 4 * ptr_size;
+ Status error;
+ lldb::addr_t userinfo =
+ process_sp->ReadPointerFromMemory(userinfo_location, error);
+ if (userinfo == LLDB_INVALID_ADDRESS || error.Fail())
+ return lldb::ChildCacheState::eRefetch;
+ InferiorSizedWord isw(userinfo, *process_sp);
+ TypeSystemClangSP scratch_ts_sp =
+ ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget());
+ if (!scratch_ts_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_child_sp = CreateValueObjectFromData(
+ "_userInfo", isw.GetAsData(process_sp->GetByteOrder()),
+ m_backend.GetExecutionContextRef(),
+ scratch_ts_sp->GetBasicType(lldb::eBasicTypeObjCID));
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ bool MightHaveChildren() override { return true; }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ static ConstString g_userInfo("_userInfo");
+ if (name == g_userInfo)
+ return 0;
+ return UINT32_MAX;
+ }
+
+private:
+ // the child here can be "real" (i.e. an actual child of the root) or
+ // synthetized from raw memory if the former, I need to store a plain pointer
+ // to it - or else a loop of references will cause this entire hierarchy of
+ // values to leak if the latter, then I need to store a SharedPointer to it -
+ // so that it only goes away when everyone else in the cluster goes away oh
+ // joy!
+ ValueObject *m_child_ptr = nullptr;
+ ValueObjectSP m_child_sp;
+};
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::NSErrorSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return nullptr;
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+ if (!runtime)
+ return nullptr;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(*valobj_sp.get()));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return nullptr;
+
+ const char *class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return nullptr;
+
+ if (!strcmp(class_name, "NSError"))
+ return (new NSErrorSyntheticFrontEnd(valobj_sp));
+ else if (!strcmp(class_name, "__NSCFError"))
+ return (new NSErrorSyntheticFrontEnd(valobj_sp));
+
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp
new file mode 100644
index 000000000000..e7ce26ea4c6f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp
@@ -0,0 +1,206 @@
+//===-- NSException.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+
+#include "Cocoa.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+#include "Plugins/Language/ObjC/NSString.h"
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp,
+ ValueObjectSP *reason_sp, ValueObjectSP *userinfo_sp,
+ ValueObjectSP *reserved_sp) {
+ ProcessSP process_sp(valobj.GetProcessSP());
+ if (!process_sp)
+ return false;
+
+ lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
+
+ CompilerType valobj_type(valobj.GetCompilerType());
+ Flags type_flags(valobj_type.GetTypeInfo());
+ if (type_flags.AllClear(eTypeHasValue)) {
+ if (valobj.IsBaseClass() && valobj.GetParent())
+ ptr = valobj.GetParent()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ } else {
+ ptr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ }
+
+ if (ptr == LLDB_INVALID_ADDRESS)
+ return false;
+ size_t ptr_size = process_sp->GetAddressByteSize();
+
+ Status error;
+ auto name = process_sp->ReadPointerFromMemory(ptr + 1 * ptr_size, error);
+ if (error.Fail() || name == LLDB_INVALID_ADDRESS)
+ return false;
+ auto reason = process_sp->ReadPointerFromMemory(ptr + 2 * ptr_size, error);
+ if (error.Fail() || reason == LLDB_INVALID_ADDRESS)
+ return false;
+ auto userinfo = process_sp->ReadPointerFromMemory(ptr + 3 * ptr_size, error);
+ if (error.Fail() || userinfo == LLDB_INVALID_ADDRESS)
+ return false;
+ auto reserved = process_sp->ReadPointerFromMemory(ptr + 4 * ptr_size, error);
+ if (error.Fail() || reserved == LLDB_INVALID_ADDRESS)
+ return false;
+
+ InferiorSizedWord name_isw(name, *process_sp);
+ InferiorSizedWord reason_isw(reason, *process_sp);
+ InferiorSizedWord userinfo_isw(userinfo, *process_sp);
+ InferiorSizedWord reserved_isw(reserved, *process_sp);
+
+ TypeSystemClangSP scratch_ts_sp =
+ ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget());
+ if (!scratch_ts_sp)
+ return false;
+
+ CompilerType voidstar =
+ scratch_ts_sp->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();
+
+ if (name_sp)
+ *name_sp = ValueObject::CreateValueObjectFromData(
+ "name", name_isw.GetAsData(process_sp->GetByteOrder()),
+ valobj.GetExecutionContextRef(), voidstar);
+ if (reason_sp)
+ *reason_sp = ValueObject::CreateValueObjectFromData(
+ "reason", reason_isw.GetAsData(process_sp->GetByteOrder()),
+ valobj.GetExecutionContextRef(), voidstar);
+ if (userinfo_sp)
+ *userinfo_sp = ValueObject::CreateValueObjectFromData(
+ "userInfo", userinfo_isw.GetAsData(process_sp->GetByteOrder()),
+ valobj.GetExecutionContextRef(), voidstar);
+ if (reserved_sp)
+ *reserved_sp = ValueObject::CreateValueObjectFromData(
+ "reserved", reserved_isw.GetAsData(process_sp->GetByteOrder()),
+ valobj.GetExecutionContextRef(), voidstar);
+
+ return true;
+}
+
+bool lldb_private::formatters::NSException_SummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ lldb::ValueObjectSP reason_sp;
+ if (!ExtractFields(valobj, nullptr, &reason_sp, nullptr, nullptr))
+ return false;
+
+ if (!reason_sp) {
+ stream.Printf("No reason");
+ return false;
+ }
+
+ StreamString reason_str_summary;
+ if (NSStringSummaryProvider(*reason_sp, reason_str_summary, options) &&
+ !reason_str_summary.Empty()) {
+ stream.Printf("%s", reason_str_summary.GetData());
+ return true;
+ } else
+ return false;
+}
+
+class NSExceptionSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSExceptionSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {}
+
+ ~NSExceptionSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override { return 4; }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ switch (idx) {
+ case 0: return m_name_sp;
+ case 1: return m_reason_sp;
+ case 2: return m_userinfo_sp;
+ case 3: return m_reserved_sp;
+ }
+ return lldb::ValueObjectSP();
+ }
+
+ lldb::ChildCacheState Update() override {
+ m_name_sp.reset();
+ m_reason_sp.reset();
+ m_userinfo_sp.reset();
+ m_reserved_sp.reset();
+
+ const auto ret = ExtractFields(m_backend, &m_name_sp, &m_reason_sp,
+ &m_userinfo_sp, &m_reserved_sp);
+
+ return ret ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+ }
+
+ bool MightHaveChildren() override { return true; }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ // NSException has 4 members:
+ // NSString *name;
+ // NSString *reason;
+ // NSDictionary *userInfo;
+ // id reserved;
+ static ConstString g_name("name");
+ static ConstString g_reason("reason");
+ static ConstString g_userInfo("userInfo");
+ static ConstString g_reserved("reserved");
+ if (name == g_name) return 0;
+ if (name == g_reason) return 1;
+ if (name == g_userInfo) return 2;
+ if (name == g_reserved) return 3;
+ return UINT32_MAX;
+ }
+
+private:
+ ValueObjectSP m_name_sp;
+ ValueObjectSP m_reason_sp;
+ ValueObjectSP m_userinfo_sp;
+ ValueObjectSP m_reserved_sp;
+};
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::NSExceptionSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return nullptr;
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+ if (!runtime)
+ return nullptr;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(*valobj_sp.get()));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return nullptr;
+
+ const char *class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return nullptr;
+
+ if (!strcmp(class_name, "NSException"))
+ return (new NSExceptionSyntheticFrontEnd(valobj_sp));
+ else if (!strcmp(class_name, "NSCFException"))
+ return (new NSExceptionSyntheticFrontEnd(valobj_sp));
+ else if (!strcmp(class_name, "__NSCFException"))
+ return (new NSExceptionSyntheticFrontEnd(valobj_sp));
+
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp
new file mode 100644
index 000000000000..a434cee09d38
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp
@@ -0,0 +1,321 @@
+//===-- NSIndexPath.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Cocoa.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
+ return (60 - (13 * (4 - i)));
+}
+
+static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {
+ return (32 - (13 * (2 - i)));
+}
+
+class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
+ m_impl(), m_uint_star_type() {
+ m_ptr_size =
+ m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
+ }
+
+ ~NSIndexPathSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ return m_impl.GetNumIndexes();
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
+ }
+
+ lldb::ChildCacheState Update() override {
+ m_impl.Clear();
+
+ auto type_system = m_backend.GetCompilerType().GetTypeSystem();
+ if (!type_system)
+ return lldb::ChildCacheState::eRefetch;
+
+ auto ast = ScratchTypeSystemClang::GetForTarget(
+ *m_backend.GetExecutionContextRef().GetTargetSP());
+ if (!ast)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_uint_star_type = ast->GetPointerSizedIntType(false);
+
+ static ConstString g__indexes("_indexes");
+ static ConstString g__length("_length");
+
+ ProcessSP process_sp = m_backend.GetProcessSP();
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return lldb::ChildCacheState::eRefetch;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(m_backend));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return lldb::ChildCacheState::eRefetch;
+
+ uint64_t info_bits(0), value_bits(0), payload(0);
+
+ if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {
+ m_impl.m_inlined.SetIndexes(payload, *process_sp);
+ m_impl.m_mode = Mode::Inlined;
+ } else {
+ ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
+ ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
+
+ bool has_indexes(false), has_length(false);
+
+ for (size_t x = 0; x < descriptor->GetNumIVars(); x++) {
+ const auto &ivar = descriptor->GetIVarAtIndex(x);
+ if (ivar.m_name == g__indexes) {
+ _indexes_id = ivar;
+ has_indexes = true;
+ } else if (ivar.m_name == g__length) {
+ _length_id = ivar;
+ has_length = true;
+ }
+
+ if (has_length && has_indexes)
+ break;
+ }
+
+ if (has_length && has_indexes) {
+ m_impl.m_outsourced.m_indexes =
+ m_backend
+ .GetSyntheticChildAtOffset(_indexes_id.m_offset,
+ m_uint_star_type.GetPointerType(),
+ true)
+ .get();
+ ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(
+ _length_id.m_offset, m_uint_star_type, true));
+ if (length_sp) {
+ m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
+ if (m_impl.m_outsourced.m_indexes)
+ m_impl.m_mode = Mode::Outsourced;
+ }
+ }
+ }
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+ }
+
+ lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }
+
+protected:
+ ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
+
+ enum class Mode { Inlined, Outsourced, Invalid };
+
+ struct Impl {
+ size_t GetNumIndexes() {
+ switch (m_mode) {
+ case Mode::Inlined:
+ return m_inlined.GetNumIndexes();
+ case Mode::Outsourced:
+ return m_outsourced.m_count;
+ default:
+ return 0;
+ }
+ }
+
+ lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
+ const CompilerType &desired_type) {
+ if (idx >= GetNumIndexes())
+ return nullptr;
+ switch (m_mode) {
+ default:
+ return nullptr;
+ case Mode::Inlined:
+ return m_inlined.GetIndexAtIndex(idx, desired_type);
+ case Mode::Outsourced:
+ return m_outsourced.GetIndexAtIndex(idx);
+ }
+ }
+
+ struct InlinedIndexes {
+ public:
+ void SetIndexes(uint64_t value, Process &p) {
+ m_indexes = value;
+ _lengthForInlinePayload(p.GetAddressByteSize());
+ m_process = &p;
+ }
+
+ size_t GetNumIndexes() { return m_count; }
+
+ lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
+ const CompilerType &desired_type) {
+ if (!m_process)
+ return nullptr;
+
+ std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
+ if (!value.second)
+ return nullptr;
+
+ Value v;
+ if (m_ptr_size == 8) {
+ Scalar scalar((unsigned long long)value.first);
+ v = Value(scalar);
+ } else {
+ Scalar scalar((unsigned int)value.first);
+ v = Value(scalar);
+ }
+
+ v.SetCompilerType(desired_type);
+
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+
+ return ValueObjectConstResult::Create(
+ m_process, v, ConstString(idx_name.GetString()));
+ }
+
+ void Clear() {
+ m_indexes = 0;
+ m_count = 0;
+ m_ptr_size = 0;
+ m_process = nullptr;
+ }
+
+ InlinedIndexes() {}
+
+ private:
+ uint64_t m_indexes = 0;
+ size_t m_count = 0;
+ uint32_t m_ptr_size = 0;
+ Process *m_process = nullptr;
+
+ // cfr. Foundation for the details of this code
+ size_t _lengthForInlinePayload(uint32_t ptr_size) {
+ m_ptr_size = ptr_size;
+ if (m_ptr_size == 8)
+ m_count = ((m_indexes >> 3) & 0x7);
+ else
+ m_count = ((m_indexes >> 3) & 0x3);
+ return m_count;
+ }
+
+ std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {
+ static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
+ if (m_ptr_size == 8) {
+ switch (pos) {
+ case 3:
+ case 2:
+ case 1:
+ case 0:
+ return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
+ PACKED_INDEX_MASK,
+ true};
+ default:
+ return {0, false};
+ }
+ } else {
+ switch (pos) {
+ case 0:
+ case 1:
+ return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
+ PACKED_INDEX_MASK,
+ true};
+ default:
+ return {0, false};
+ }
+ }
+ return {0, false};
+ }
+ };
+
+ struct OutsourcedIndexes {
+ lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {
+ if (m_indexes) {
+ ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
+ return index_sp;
+ }
+ return nullptr;
+ }
+
+ void Clear() {
+ m_indexes = nullptr;
+ m_count = 0;
+ }
+
+ OutsourcedIndexes() {}
+
+ ValueObject *m_indexes = nullptr;
+ size_t m_count = 0;
+ };
+
+ union {
+ struct InlinedIndexes m_inlined;
+ struct OutsourcedIndexes m_outsourced;
+ };
+
+ void Clear() {
+ switch (m_mode) {
+ case Mode::Inlined:
+ m_inlined.Clear();
+ break;
+ case Mode::Outsourced:
+ m_outsourced.Clear();
+ break;
+ case Mode::Invalid:
+ break;
+ }
+ m_mode = Mode::Invalid;
+ }
+
+ Impl() {}
+
+ Mode m_mode = Mode::Invalid;
+ } m_impl;
+
+ uint32_t m_ptr_size = 0;
+ CompilerType m_uint_star_type;
+};
+
+namespace lldb_private {
+namespace formatters {
+
+SyntheticChildrenFrontEnd *
+NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new NSIndexPathSyntheticFrontEnd(valobj_sp);
+ return nullptr;
+}
+
+} // namespace formatters
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp
new file mode 100644
index 000000000000..7d0a6a507211
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp
@@ -0,0 +1,831 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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/Target/Language.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
+NSSet_Additionals::GetAdditionalSummaries() {
+ static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
+ return g_map;
+}
+
+std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
+NSSet_Additionals::GetAdditionalSynthetics() {
+ static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
+ g_map;
+ return g_map;
+}
+
+namespace lldb_private {
+namespace formatters {
+class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~NSSetISyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ struct DataDescriptor_32 {
+ uint32_t _used : 26;
+ uint32_t _szidx : 6;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _used : 58;
+ uint32_t _szidx : 6;
+ };
+
+ struct SetItemDescriptor {
+ lldb::addr_t item_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size = 8;
+ DataDescriptor_32 *m_data_32 = nullptr;
+ DataDescriptor_64 *m_data_64 = nullptr;
+ lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;
+ std::vector<SetItemDescriptor> m_children;
+};
+
+class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState 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 = 8;
+ lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
+
+ CFBasicHash m_hashtable;
+
+ CompilerType m_pair_type;
+ std::vector<SetItemDescriptor> m_children;
+};
+
+template <typename D32, typename D64>
+class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~GenericNSSetMSyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState 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 = 8;
+ D32 *m_data_32;
+ D64 *m_data_64;
+ std::vector<SetItemDescriptor> m_children;
+};
+
+namespace Foundation1300 {
+ struct DataDescriptor_32 {
+ uint32_t _used : 26;
+ uint32_t _size;
+ uint32_t _mutations;
+ uint32_t _objs_addr;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _used : 58;
+ uint64_t _size;
+ uint64_t _mutations;
+ uint64_t _objs_addr;
+ };
+
+ using NSSetMSyntheticFrontEnd =
+ GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+}
+
+namespace Foundation1428 {
+ struct DataDescriptor_32 {
+ uint32_t _used : 26;
+ uint32_t _size;
+ uint32_t _objs_addr;
+ uint32_t _mutations;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _used : 58;
+ uint64_t _size;
+ uint64_t _objs_addr;
+ uint64_t _mutations;
+ };
+
+ using NSSetMSyntheticFrontEnd =
+ GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+}
+
+namespace Foundation1437 {
+ struct DataDescriptor_32 {
+ uint32_t _cow;
+ // __table storage
+ uint32_t _objs_addr;
+ uint32_t _muts;
+ uint32_t _used : 26;
+ uint32_t _szidx : 6;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t _cow;
+ // __Table storage
+ uint64_t _objs_addr;
+ uint32_t _muts;
+ uint32_t _used : 26;
+ uint32_t _szidx : 6;
+ };
+
+ using NSSetMSyntheticFrontEnd =
+ GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+
+ template <typename DD>
+ uint64_t
+ __NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr,
+ Status &error) {
+ const lldb::addr_t start_of_descriptor =
+ valobj_addr + process.GetAddressByteSize();
+ DD descriptor = DD();
+ process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
+ error);
+ if (error.Fail()) {
+ return 0;
+ }
+ return descriptor._used;
+ }
+
+ uint64_t
+ __NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
+ Status &error) {
+ if (process.GetAddressByteSize() == 4) {
+ return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error);
+ } else {
+ return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error);
+ }
+ }
+}
+
+class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~NSSetCodeRunningSyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+};
+} // namespace formatters
+} // namespace lldb_private
+
+template <bool cf_style>
+bool lldb_private::formatters::NSSetSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSSet");
+
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+ bool is_64bit = (ptr_size == 8);
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t value = 0;
+
+ ConstString class_name(descriptor->GetClassName());
+
+ 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 (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 (class_name == g_SetM) {
+ AppleObjCRuntime *apple_runtime =
+ llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
+ Status error;
+ if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
+ value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error);
+ } else {
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
+ }
+ 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), end = map.end();
+ if (iter != end)
+ return iter->second(valobj, stream, options);
+ else
+ return false;
+ }
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(options.GetLanguage()))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ stream << prefix;
+ stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");
+ stream << suffix;
+ return true;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::NSSetSyntheticFrontEndCreator(
+ CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return nullptr;
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+ if (!runtime)
+ return nullptr;
+
+ CompilerType valobj_type(valobj_sp->GetCompilerType());
+ Flags flags(valobj_type.GetTypeInfo());
+
+ if (flags.IsClear(eTypeIsPointer)) {
+ Status error;
+ valobj_sp = valobj_sp->AddressOf(error);
+ if (error.Fail() || !valobj_sp)
+ return nullptr;
+ }
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(*valobj_sp));
+
+ if (!descriptor || !descriptor->IsValid())
+ return nullptr;
+
+ ConstString class_name = descriptor->GetClassName();
+
+ 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 (class_name == g_SetI || class_name == g_OrderedSetI) {
+ return (new NSSetISyntheticFrontEnd(valobj_sp));
+ } else if (class_name == g_SetM) {
+ AppleObjCRuntime *apple_runtime =
+ llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
+ if (apple_runtime) {
+ if (apple_runtime->GetFoundationVersion() >= 1437)
+ return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp));
+ else if (apple_runtime->GetFoundationVersion() >= 1428)
+ return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp));
+ else
+ return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
+ } 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), end = map.end();
+ if (iter != end)
+ return iter->second(synth, valobj_sp);
+ return nullptr;
+ }
+}
+
+lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref() {
+ if (valobj_sp)
+ Update();
+}
+
+lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+size_t
+lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+llvm::Expected<uint32_t>
+lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
+ m_children.clear();
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ m_ptr_size = 0;
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ Status error;
+ if (m_ptr_size == 4) {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ error);
+ } else {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ error);
+ }
+ if (error.Fail())
+ return lldb::ChildCacheState::eRefetch;
+ m_data_ptr = data_location + m_ptr_size;
+ return lldb::ChildCacheState::eReuse;
+}
+
+bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ uint32_t num_children = CalculateNumChildrenIgnoringErrors();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty()) {
+ // do the scan phase
+ lldb::addr_t obj_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ while (tries < num_children) {
+ obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
+ obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!obj_at_idx)
+ continue;
+ tries++;
+
+ SetItemDescriptor descriptor = {obj_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) {
+ auto ptr_size = process_sp->GetAddressByteSize();
+ DataBufferHeap buffer(ptr_size, 0);
+ switch (ptr_size) {
+ case 0: // architecture has no clue - fail
+ return lldb::ValueObjectSP();
+ case 4:
+ *reinterpret_cast<uint32_t *>(buffer.GetBytes()) =
+ static_cast<uint32_t>(set_item.item_ptr);
+ break;
+ case 8:
+ *reinterpret_cast<uint64_t *>(buffer.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.GetBytes(), buffer.GetByteSize(),
+ process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize());
+
+ set_item.valobj_sp = CreateValueObjectFromData(
+ idx_name.GetString(), data, m_exe_ctx_ref,
+ m_backend.GetCompilerType().GetBasicTypeFromAST(
+ lldb::eBasicTypeObjCID));
+ }
+ return set_item.valobj_sp;
+}
+
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), 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 >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+llvm::Expected<uint32_t>
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_hashtable.IsValid())
+ return 0;
+ return m_hashtable.GetCount();
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)
+ ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
+
+ const uint32_t num_children = CalculateNumChildrenIgnoringErrors();
+
+ 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) {
+
+ WritableDataBufferSP 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(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
+ m_data_32(nullptr), m_data_64(nullptr) {
+ if (valobj_sp)
+ Update();
+}
+
+template <typename D32, typename D64>
+lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::
+ GenericNSSetMSyntheticFrontEnd::~GenericNSSetMSyntheticFrontEnd() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+template <typename D32, typename D64>
+size_t
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName(
+ ConstString name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+template <typename D32, typename D64>
+llvm::Expected<uint32_t>
+lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<
+ D32, D64>::CalculateNumChildren() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);
+}
+
+template <typename D32, typename D64>
+lldb::ChildCacheState
+lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ Status error;
+ if (m_ptr_size == 4) {
+ m_data_32 = new D32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
+ error);
+ } else {
+ m_data_64 = new D64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
+ error);
+ }
+ return error.Success() ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+template <typename D32, typename D64>
+bool
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() {
+ return true;
+}
+
+template <typename D32, typename D64>
+lldb::ValueObjectSP
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(uint32_t idx) {
+ lldb::addr_t m_objs_addr =
+ (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
+
+ uint32_t num_children = CalculateNumChildrenIgnoringErrors();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty()) {
+ // do the scan phase
+ lldb::addr_t obj_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ while (tries < num_children) {
+ obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
+ obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!obj_at_idx)
+ continue;
+ tries++;
+
+ SetItemDescriptor descriptor = {obj_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) {
+ auto ptr_size = process_sp->GetAddressByteSize();
+ DataBufferHeap buffer(ptr_size, 0);
+ switch (ptr_size) {
+ case 0: // architecture has no clue?? - fail
+ return lldb::ValueObjectSP();
+ case 4:
+ *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
+ break;
+ case 8:
+ *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
+ break;
+ default:
+ assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
+ }
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+
+ DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
+ process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize());
+
+ 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 bool lldb_private::formatters::NSSetSummaryProvider<true>(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
+
+template bool lldb_private::formatters::NSSetSummaryProvider<false>(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.h
new file mode 100644
index 000000000000..3ad1f694befe
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.h
@@ -0,0 +1,39 @@
+//===-- NSSet.h ---------------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSET_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSET_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+template <bool cf_style>
+bool NSSetSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+SyntheticChildrenFrontEnd *NSSetSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+class NSSet_Additionals {
+public:
+ static std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
+ GetAdditionalSummaries();
+
+ static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
+ GetAdditionalSynthetics();
+};
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSET_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.cpp
new file mode 100644
index 000000000000..0a30737d9723
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.cpp
@@ -0,0 +1,370 @@
+//===-- NSString.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NSString.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
+NSString_Additionals::GetAdditionalSummaries() {
+ static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
+ return g_map;
+}
+
+bool lldb_private::formatters::NSStringSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSString");
+
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(
+ runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ ConstString class_name_cs = descriptor->GetClassName();
+ llvm::StringRef class_name = class_name_cs.GetStringRef();
+
+ if (class_name.empty())
+ return false;
+
+ bool is_tagged_ptr = class_name == "NSTaggedPointerString" &&
+ descriptor->GetTaggedPointerInfo();
+ // for a tagged pointer, the descriptor has everything we need
+ if (is_tagged_ptr)
+ return NSTaggedString_SummaryProvider(valobj, descriptor, stream,
+ summary_options);
+
+ auto &additionals_map(NSString_Additionals::GetAdditionalSummaries());
+ auto iter = additionals_map.find(class_name_cs), end = additionals_map.end();
+ if (iter != end)
+ return iter->second(valobj, stream, summary_options);
+
+ // if not a tagged pointer that we know about, try the normal route
+ uint64_t info_bits_location = valobj_addr + ptr_size;
+ if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
+ info_bits_location += 3;
+
+ Status error;
+
+ uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(
+ info_bits_location, 1, 0, error);
+ if (error.Fail())
+ return false;
+
+ bool is_mutable = (info_bits & 1) == 1;
+ bool is_inline = (info_bits & 0x60) == 0;
+ bool has_explicit_length = (info_bits & (1 | 4)) != 4;
+ bool is_unicode = (info_bits & 0x10) == 0x10;
+ bool is_path_store = class_name == "NSPathStore2";
+ bool has_null = (info_bits & 8) == 8;
+
+ size_t explicit_length = 0;
+ if (!has_null && has_explicit_length && !is_path_store) {
+ lldb::addr_t explicit_length_offset = 2 * ptr_size;
+ if (is_mutable && !is_inline)
+ explicit_length_offset =
+ explicit_length_offset + ptr_size; // notInlineMutable.length;
+ else if (is_inline)
+ explicit_length = explicit_length + 0; // inline1.length;
+ else if (!is_inline && !is_mutable)
+ explicit_length_offset =
+ explicit_length_offset + ptr_size; // notInlineImmutable1.length;
+ else
+ explicit_length_offset = 0;
+
+ if (explicit_length_offset) {
+ explicit_length_offset = valobj_addr + explicit_length_offset;
+ explicit_length = process_sp->ReadUnsignedIntegerFromMemory(
+ explicit_length_offset, 4, 0, error);
+ }
+ }
+
+ const llvm::StringSet<> supported_string_classes = {
+ "NSString", "CFMutableStringRef",
+ "CFStringRef", "__NSCFConstantString",
+ "__NSCFString", "NSCFConstantString",
+ "NSCFString", "NSPathStore2"};
+ if (supported_string_classes.count(class_name) == 0) {
+ // not one of us - but tell me class name
+ stream.Printf("class name = %s", class_name_cs.GetCString());
+ return true;
+ }
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(summary_options.GetLanguage()))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
+ options.SetPrefixToken(prefix.str());
+ options.SetSuffixToken(suffix.str());
+
+ if (is_mutable) {
+ uint64_t location = 2 * ptr_size + valobj_addr;
+ location = process_sp->ReadPointerFromMemory(location, error);
+ if (error.Fail())
+ return false;
+ if (has_explicit_length && is_unicode) {
+ options.SetLocation(location);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetQuote('"');
+ options.SetSourceSize(explicit_length);
+ options.SetHasSourceSize(has_explicit_length);
+ options.SetNeedsZeroTermination(false);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() ==
+ TypeSummaryCapping::eTypeSummaryUncapped);
+ options.SetBinaryZeroIsTerminator(false);
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::UTF16>(options);
+ } else {
+ options.SetLocation(location + 1);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetSourceSize(explicit_length);
+ options.SetHasSourceSize(has_explicit_length);
+ options.SetNeedsZeroTermination(false);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() ==
+ TypeSummaryCapping::eTypeSummaryUncapped);
+ options.SetBinaryZeroIsTerminator(false);
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::ASCII>(options);
+ }
+ } else if (is_inline && has_explicit_length && !is_unicode &&
+ !is_path_store && !is_mutable) {
+ uint64_t location = 3 * ptr_size + valobj_addr;
+
+ options.SetLocation(location);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetQuote('"');
+ options.SetSourceSize(explicit_length);
+ options.SetHasSourceSize(has_explicit_length);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() ==
+ TypeSummaryCapping::eTypeSummaryUncapped);
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::ASCII>(options);
+ } else if (is_unicode) {
+ uint64_t location = valobj_addr + 2 * ptr_size;
+ if (is_inline) {
+ if (!has_explicit_length) {
+ return false;
+ } else
+ location += ptr_size;
+ } else {
+ location = process_sp->ReadPointerFromMemory(location, error);
+ if (error.Fail())
+ return false;
+ }
+ options.SetLocation(location);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetQuote('"');
+ options.SetSourceSize(explicit_length);
+ options.SetHasSourceSize(has_explicit_length);
+ options.SetNeedsZeroTermination(!has_explicit_length);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() ==
+ TypeSummaryCapping::eTypeSummaryUncapped);
+ options.SetBinaryZeroIsTerminator(!has_explicit_length);
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::UTF16>(options);
+ } else if (is_path_store) {
+ // _lengthAndRefCount is the first ivar of NSPathStore2 (after the isa).
+ uint64_t length_ivar_offset = 1 * ptr_size;
+ CompilerType length_type = valobj.GetCompilerType().GetBasicTypeFromAST(
+ lldb::eBasicTypeUnsignedInt);
+ ValueObjectSP length_valobj_sp =
+ valobj.GetSyntheticChildAtOffset(length_ivar_offset, length_type, true,
+ ConstString("_lengthAndRefCount"));
+ if (!length_valobj_sp)
+ return false;
+ // Get the length out of _lengthAndRefCount.
+ explicit_length = length_valobj_sp->GetValueAsUnsigned(0) >> 20;
+ lldb::addr_t location = valobj.GetValueAsUnsigned(0) + ptr_size + 4;
+
+ options.SetLocation(location);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetQuote('"');
+ options.SetSourceSize(explicit_length);
+ options.SetHasSourceSize(has_explicit_length);
+ options.SetNeedsZeroTermination(!has_explicit_length);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() ==
+ TypeSummaryCapping::eTypeSummaryUncapped);
+ options.SetBinaryZeroIsTerminator(!has_explicit_length);
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::UTF16>(options);
+ } else if (is_inline) {
+ uint64_t location = valobj_addr + 2 * ptr_size;
+ if (!has_explicit_length) {
+ // in this kind of string, the byte before the string content is a length
+ // byte so let's try and use it to handle the embedded NUL case
+ Status error;
+ explicit_length =
+ process_sp->ReadUnsignedIntegerFromMemory(location, 1, 0, error);
+ has_explicit_length = !(error.Fail() || explicit_length == 0);
+ location++;
+ }
+ options.SetLocation(location);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetSourceSize(explicit_length);
+ options.SetHasSourceSize(has_explicit_length);
+ options.SetNeedsZeroTermination(!has_explicit_length);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() ==
+ TypeSummaryCapping::eTypeSummaryUncapped);
+ options.SetBinaryZeroIsTerminator(!has_explicit_length);
+ if (has_explicit_length)
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::UTF8>(options);
+ else
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::ASCII>(options);
+ } else {
+ uint64_t location = valobj_addr + 2 * ptr_size;
+ location = process_sp->ReadPointerFromMemory(location, error);
+ if (error.Fail())
+ return false;
+ if (has_explicit_length && !has_null)
+ explicit_length++; // account for the fact that there is no NULL and we
+ // need to have one added
+ options.SetLocation(location);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetSourceSize(explicit_length);
+ options.SetHasSourceSize(has_explicit_length);
+ options.SetIgnoreMaxLength(summary_options.GetCapping() ==
+ TypeSummaryCapping::eTypeSummaryUncapped);
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::ASCII>(options);
+ }
+}
+
+bool lldb_private::formatters::NSAttributedStringSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ TargetSP target_sp(valobj.GetTargetSP());
+ if (!target_sp)
+ return false;
+ uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
+ uint64_t pointer_value = valobj.GetValueAsUnsigned(0);
+ if (!pointer_value)
+ return false;
+ pointer_value += addr_size;
+ CompilerType type(valobj.GetCompilerType());
+ ExecutionContext exe_ctx(target_sp, false);
+ ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress(
+ "string_ptr", pointer_value, exe_ctx, type));
+ if (!child_ptr_sp)
+ return false;
+ DataExtractor data;
+ Status error;
+ child_ptr_sp->GetData(data, error);
+ if (error.Fail())
+ return false;
+ ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData(
+ "string_data", data, exe_ctx, type));
+ child_sp->GetValueAsUnsigned(0);
+ if (child_sp)
+ return NSStringSummaryProvider(*child_sp, stream, options);
+ return false;
+}
+
+bool lldb_private::formatters::NSMutableAttributedStringSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ return NSAttributedStringSummaryProvider(valobj, stream, options);
+}
+
+bool lldb_private::formatters::NSTaggedString_SummaryProvider(
+ ValueObject &valobj, ObjCLanguageRuntime::ClassDescriptorSP descriptor,
+ Stream &stream, const TypeSummaryOptions &summary_options) {
+ static constexpr llvm::StringLiteral g_TypeHint("NSString");
+
+ if (!descriptor)
+ return false;
+ uint64_t len_bits = 0, data_bits = 0;
+ if (!descriptor->GetTaggedPointerInfo(&len_bits, &data_bits, nullptr))
+ return false;
+
+ static const int g_MaxNonBitmaskedLen = 7; // TAGGED_STRING_UNPACKED_MAXLEN
+ static const int g_SixbitMaxLen = 9;
+ static const int g_fiveBitMaxLen = 11;
+
+ static const char *sixBitToCharLookup = "eilotrm.apdnsIc ufkMShjTRxgC4013"
+ "bDNvwyUL2O856P-B79AFKEWV_zGJ/HYX";
+
+ if (len_bits > g_fiveBitMaxLen)
+ return false;
+
+ llvm::StringRef prefix, suffix;
+ if (Language *language = Language::FindPlugin(summary_options.GetLanguage()))
+ std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
+
+ // this is a fairly ugly trick - pretend that the numeric value is actually a
+ // char* this works under a few assumptions: little endian architecture
+ // sizeof(uint64_t) > g_MaxNonBitmaskedLen
+ if (len_bits <= g_MaxNonBitmaskedLen) {
+ stream << prefix;
+ stream.Printf("\"%s\"", (const char *)&data_bits);
+ stream << suffix;
+ return true;
+ }
+
+ // if the data is bitmasked, we need to actually process the bytes
+ uint8_t bitmask = 0;
+ uint8_t shift_offset = 0;
+
+ if (len_bits <= g_SixbitMaxLen) {
+ bitmask = 0x03f;
+ shift_offset = 6;
+ } else {
+ bitmask = 0x01f;
+ shift_offset = 5;
+ }
+
+ std::vector<uint8_t> bytes;
+ bytes.resize(len_bits);
+ for (; len_bits > 0; data_bits >>= shift_offset, --len_bits) {
+ uint8_t packed = data_bits & bitmask;
+ bytes.insert(bytes.begin(), sixBitToCharLookup[packed]);
+ }
+
+ stream << prefix;
+ stream.Printf("\"%s\"", &bytes[0]);
+ stream << suffix;
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.h
new file mode 100644
index 000000000000..a68cc6c056b0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSString.h
@@ -0,0 +1,42 @@
+//===-- NSString.h ---------------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSTRING_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSTRING_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/Stream.h"
+
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+
+namespace lldb_private {
+namespace formatters {
+bool NSStringSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSTaggedString_SummaryProvider(
+ ValueObject &valobj, ObjCLanguageRuntime::ClassDescriptorSP descriptor,
+ Stream &stream, const TypeSummaryOptions &summary_options);
+
+bool NSAttributedStringSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool NSMutableAttributedStringSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
+
+class NSString_Additionals {
+public:
+ static std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
+ GetAdditionalSummaries();
+};
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_NSSTRING_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCConstants.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCConstants.h
new file mode 100644
index 000000000000..c7c498d4cab3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCConstants.h
@@ -0,0 +1,44 @@
+//===-- ObjCConstants.h------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCCONSTANTS_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCCONSTANTS_H
+
+// Objective-C Type Encoding
+#define _C_ID '@'
+#define _C_CLASS '#'
+#define _C_SEL ':'
+#define _C_CHR 'c'
+#define _C_UCHR 'C'
+#define _C_SHT 's'
+#define _C_USHT 'S'
+#define _C_INT 'i'
+#define _C_UINT 'I'
+#define _C_LNG 'l'
+#define _C_ULNG 'L'
+#define _C_LNG_LNG 'q'
+#define _C_ULNG_LNG 'Q'
+#define _C_FLT 'f'
+#define _C_DBL 'd'
+#define _C_BFLD 'b'
+#define _C_BOOL 'B'
+#define _C_VOID 'v'
+#define _C_UNDEF '?'
+#define _C_PTR '^'
+#define _C_CHARPTR '*'
+#define _C_ATOM '%'
+#define _C_ARY_B '['
+#define _C_ARY_E ']'
+#define _C_UNION_B '('
+#define _C_UNION_E ')'
+#define _C_STRUCT_B '{'
+#define _C_STRUCT_E '}'
+#define _C_VECTOR '!'
+#define _C_CONST 'r'
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCCONSTANTS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
new file mode 100644
index 000000000000..742ae7b14945
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -0,0 +1,1042 @@
+//===-- ObjCLanguage.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <mutex>
+
+#include "ObjCLanguage.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "llvm/Support/Threading.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+
+#include "CF.h"
+#include "Cocoa.h"
+#include "CoreMedia.h"
+#include "NSDictionary.h"
+#include "NSSet.h"
+#include "NSString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+LLDB_PLUGIN_DEFINE(ObjCLanguage)
+
+void ObjCLanguage::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(), "Objective-C Language",
+ CreateInstance);
+}
+
+void ObjCLanguage::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+// Static Functions
+
+Language *ObjCLanguage::CreateInstance(lldb::LanguageType language) {
+ switch (language) {
+ case lldb::eLanguageTypeObjC:
+ return new ObjCLanguage();
+ default:
+ return nullptr;
+ }
+}
+
+std::optional<const ObjCLanguage::MethodName>
+ObjCLanguage::MethodName::Create(llvm::StringRef name, bool strict) {
+ if (name.empty())
+ return std::nullopt;
+
+ // Objective-C method minimum requirements:
+ // - If `strict` is true, must start with '-' or '+' (1 char)
+ // - Must be followed by '[' (1 char)
+ // - Must have at least one character for class name (1 char)
+ // - Must have a space between class name and method name (1 char)
+ // - Must have at least one character for method name (1 char)
+ // - Must be end with ']' (1 char)
+ // This means that the minimum size is 5 characters (6 if `strict`)
+ // e.g. [a a] (-[a a] or +[a a] if `strict`)
+
+ // We can check length and ending invariants first
+ if (name.size() < (5 + (strict ? 1 : 0)) || name.back() != ']')
+ return std::nullopt;
+
+ // Figure out type
+ Type type = eTypeUnspecified;
+ if (name.starts_with("+["))
+ type = eTypeClassMethod;
+ else if (name.starts_with("-["))
+ type = eTypeInstanceMethod;
+
+ // If there's no type and it's strict, this is invalid
+ if (strict && type == eTypeUnspecified)
+ return std::nullopt;
+
+ // If not strict and type unspecified, make sure we start with '['
+ if (type == eTypeUnspecified && name.front() != '[')
+ return std::nullopt;
+
+ // If we've gotten here, we're confident that this looks enough like an
+ // Objective-C method to treat it like one.
+ ObjCLanguage::MethodName method_name(name, type);
+ return method_name;
+}
+
+llvm::StringRef ObjCLanguage::MethodName::GetClassName() const {
+ llvm::StringRef full = m_full;
+ const size_t class_start_pos = (full.front() == '[' ? 1 : 2);
+ const size_t paren_pos = full.find('(', class_start_pos);
+ // If there's a category we want to stop there
+ if (paren_pos != llvm::StringRef::npos)
+ return full.substr(class_start_pos, paren_pos - class_start_pos);
+
+ // Otherwise we find the space separating the class and method
+ const size_t space_pos = full.find(' ', class_start_pos);
+ return full.substr(class_start_pos, space_pos - class_start_pos);
+}
+
+llvm::StringRef ObjCLanguage::MethodName::GetClassNameWithCategory() const {
+ llvm::StringRef full = m_full;
+ const size_t class_start_pos = (full.front() == '[' ? 1 : 2);
+ const size_t space_pos = full.find(' ', class_start_pos);
+ return full.substr(class_start_pos, space_pos - class_start_pos);
+}
+
+llvm::StringRef ObjCLanguage::MethodName::GetSelector() const {
+ llvm::StringRef full = m_full;
+ const size_t space_pos = full.find(' ');
+ if (space_pos == llvm::StringRef::npos)
+ return llvm::StringRef();
+ const size_t closing_bracket = full.find(']', space_pos);
+ return full.substr(space_pos + 1, closing_bracket - space_pos - 1);
+}
+
+llvm::StringRef ObjCLanguage::MethodName::GetCategory() const {
+ llvm::StringRef full = m_full;
+ const size_t open_paren_pos = full.find('(');
+ const size_t close_paren_pos = full.find(')');
+
+ if (open_paren_pos == llvm::StringRef::npos ||
+ close_paren_pos == llvm::StringRef::npos)
+ return llvm::StringRef();
+
+ return full.substr(open_paren_pos + 1,
+ close_paren_pos - (open_paren_pos + 1));
+}
+
+std::string ObjCLanguage::MethodName::GetFullNameWithoutCategory() const {
+ llvm::StringRef full = m_full;
+ const size_t open_paren_pos = full.find('(');
+ const size_t close_paren_pos = full.find(')');
+ if (open_paren_pos == llvm::StringRef::npos ||
+ close_paren_pos == llvm::StringRef::npos)
+ return std::string();
+
+ llvm::StringRef class_name = GetClassName();
+ llvm::StringRef selector_name = GetSelector();
+
+ // Compute the total size to avoid reallocations
+ // class name + selector name + '[' + ' ' + ']'
+ size_t total_size = class_name.size() + selector_name.size() + 3;
+ if (m_type != eTypeUnspecified)
+ total_size++; // For + or -
+
+ std::string name_sans_category;
+ name_sans_category.reserve(total_size);
+
+ if (m_type == eTypeClassMethod)
+ name_sans_category += '+';
+ else if (m_type == eTypeInstanceMethod)
+ name_sans_category += '-';
+
+ name_sans_category += '[';
+ name_sans_category.append(class_name.data(), class_name.size());
+ name_sans_category += ' ';
+ name_sans_category.append(selector_name.data(), selector_name.size());
+ name_sans_category += ']';
+
+ return name_sans_category;
+}
+
+std::vector<Language::MethodNameVariant>
+ObjCLanguage::GetMethodNameVariants(ConstString method_name) const {
+ std::vector<Language::MethodNameVariant> variant_names;
+ std::optional<const ObjCLanguage::MethodName> objc_method =
+ ObjCLanguage::MethodName::Create(method_name.GetStringRef(), false);
+ if (!objc_method)
+ return variant_names;
+
+ variant_names.emplace_back(ConstString(objc_method->GetSelector()),
+ lldb::eFunctionNameTypeSelector);
+
+ const std::string name_sans_category =
+ objc_method->GetFullNameWithoutCategory();
+
+ if (objc_method->IsClassMethod() || objc_method->IsInstanceMethod()) {
+ if (!name_sans_category.empty())
+ variant_names.emplace_back(ConstString(name_sans_category.c_str()),
+ lldb::eFunctionNameTypeFull);
+ } else {
+ StreamString strm;
+
+ strm.Printf("+%s", objc_method->GetFullName().c_str());
+ variant_names.emplace_back(ConstString(strm.GetString()),
+ lldb::eFunctionNameTypeFull);
+ strm.Clear();
+
+ strm.Printf("-%s", objc_method->GetFullName().c_str());
+ variant_names.emplace_back(ConstString(strm.GetString()),
+ lldb::eFunctionNameTypeFull);
+ strm.Clear();
+
+ if (!name_sans_category.empty()) {
+ strm.Printf("+%s", name_sans_category.c_str());
+ variant_names.emplace_back(ConstString(strm.GetString()),
+ lldb::eFunctionNameTypeFull);
+ strm.Clear();
+
+ strm.Printf("-%s", name_sans_category.c_str());
+ variant_names.emplace_back(ConstString(strm.GetString()),
+ lldb::eFunctionNameTypeFull);
+ }
+ }
+
+ return variant_names;
+}
+
+bool ObjCLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
+ ConstString demangled_name = mangled.GetDemangledName();
+ if (!demangled_name)
+ return false;
+ return ObjCLanguage::IsPossibleObjCMethodName(demangled_name.GetCString());
+}
+
+static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) {
+ if (!objc_category_sp)
+ return;
+
+ TypeSummaryImpl::Flags objc_flags;
+ objc_flags.SetCascades(false)
+ .SetSkipPointers(true)
+ .SetSkipReferences(true)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(true)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ lldb::TypeSummaryImplSP ObjC_BOOL_summary(new CXXFunctionSummaryFormat(
+ objc_flags, lldb_private::formatters::ObjCBOOLSummaryProvider, ""));
+ objc_category_sp->AddTypeSummary("BOOL", eFormatterMatchExact,
+ ObjC_BOOL_summary);
+ objc_category_sp->AddTypeSummary("BOOL &", eFormatterMatchExact,
+ ObjC_BOOL_summary);
+ objc_category_sp->AddTypeSummary("BOOL *", eFormatterMatchExact,
+ ObjC_BOOL_summary);
+
+ // we need to skip pointers here since we are special casing a SEL* when
+ // retrieving its value
+ objc_flags.SetSkipPointers(true);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::ObjCSELSummaryProvider<false>,
+ "SEL summary provider", "SEL", objc_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::ObjCSELSummaryProvider<false>,
+ "SEL summary provider", "struct objc_selector", objc_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::ObjCSELSummaryProvider<false>,
+ "SEL summary provider", "objc_selector", objc_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::ObjCSELSummaryProvider<true>,
+ "SEL summary provider", "objc_selector *", objc_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::ObjCSELSummaryProvider<true>,
+ "SEL summary provider", "SEL *", objc_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::ObjCClassSummaryProvider,
+ "Class summary provider", "Class", objc_flags);
+
+ SyntheticChildren::Flags class_synth_flags;
+ class_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
+ false);
+
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::ObjCClassSyntheticFrontEndCreator,
+ "Class synthetic children", "Class", class_synth_flags);
+
+ objc_flags.SetSkipPointers(false);
+ objc_flags.SetCascades(true);
+ objc_flags.SetSkipReferences(false);
+
+ AddStringSummary(objc_category_sp, "${var.__FuncPtr%A}",
+ "__block_literal_generic", objc_flags);
+
+ AddStringSummary(objc_category_sp,
+ "${var.years} years, ${var.months} "
+ "months, ${var.days} days, ${var.hours} "
+ "hours, ${var.minutes} minutes "
+ "${var.seconds} seconds",
+ "CFGregorianUnits", objc_flags);
+ AddStringSummary(objc_category_sp,
+ "location=${var.location} length=${var.length}", "CFRange",
+ objc_flags);
+
+ AddStringSummary(objc_category_sp,
+ "location=${var.location}, length=${var.length}", "NSRange",
+ objc_flags);
+ AddStringSummary(objc_category_sp, "(${var.origin}, ${var.size}), ...",
+ "NSRectArray", objc_flags);
+
+ AddOneLineSummary(objc_category_sp, "NSPoint", objc_flags);
+ AddOneLineSummary(objc_category_sp, "NSSize", objc_flags);
+ AddOneLineSummary(objc_category_sp, "NSRect", objc_flags);
+
+ AddOneLineSummary(objc_category_sp, "CGSize", objc_flags);
+ AddOneLineSummary(objc_category_sp, "CGPoint", objc_flags);
+ AddOneLineSummary(objc_category_sp, "CGRect", objc_flags);
+
+ AddStringSummary(objc_category_sp,
+ "red=${var.red} green=${var.green} blue=${var.blue}",
+ "RGBColor", objc_flags);
+ AddStringSummary(
+ objc_category_sp,
+ "(t=${var.top}, l=${var.left}, b=${var.bottom}, r=${var.right})", "Rect",
+ objc_flags);
+ AddStringSummary(objc_category_sp, "{(v=${var.v}, h=${var.h})}", "Point",
+ objc_flags);
+ AddStringSummary(objc_category_sp,
+ "${var.month}/${var.day}/${var.year} ${var.hour} "
+ ":${var.minute} :${var.second} dayOfWeek:${var.dayOfWeek}",
+ "DateTimeRect *", objc_flags);
+ AddStringSummary(objc_category_sp,
+ "${var.ld.month}/${var.ld.day}/"
+ "${var.ld.year} ${var.ld.hour} "
+ ":${var.ld.minute} :${var.ld.second} "
+ "dayOfWeek:${var.ld.dayOfWeek}",
+ "LongDateRect", objc_flags);
+ AddStringSummary(objc_category_sp, "(x=${var.x}, y=${var.y})", "HIPoint",
+ objc_flags);
+ AddStringSummary(objc_category_sp, "origin=${var.origin} size=${var.size}",
+ "HIRect", objc_flags);
+
+ TypeSummaryImpl::Flags appkit_flags;
+ appkit_flags.SetCascades(true)
+ .SetSkipPointers(false)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(false)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ appkit_flags.SetDontShowChildren(false);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "NSArray", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "NSConstantArray", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "NSMutableArray", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "__NSArrayI", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "__NSArray0", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "__NSSingleObjectArrayI", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "__NSArrayM", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "__NSCFArray", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "_NSCallStackArray", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "CFArrayRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSArraySummaryProvider,
+ "NSArray summary provider", "CFMutableArrayRef", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<false>,
+ "NSDictionary summary provider", "NSDictionary", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<false>,
+ "NSDictionary summary provider", "NSConstantDictionary",
+ appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<false>,
+ "NSDictionary summary provider", "NSMutableDictionary",
+ appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<false>,
+ "NSDictionary summary provider", "__NSCFDictionary",
+ appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<false>,
+ "NSDictionary summary provider", "__NSDictionaryI",
+ appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<false>,
+ "NSDictionary summary provider", "__NSSingleEntryDictionaryI",
+ appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<false>,
+ "NSDictionary summary provider", "__NSDictionaryM",
+ appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<true>,
+ "NSDictionary summary provider", "CFDictionaryRef",
+ appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<true>,
+ "NSDictionary summary provider", "__CFDictionary",
+ appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDictionarySummaryProvider<true>,
+ "NSDictionary summary provider", "CFMutableDictionaryRef",
+ appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "NSSet summary", "NSSet", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "NSMutableSet summary", "NSMutableSet", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<true>,
+ "CFSetRef summary", "CFSetRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<true>,
+ "CFMutableSetRef summary", "CFMutableSetRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "__NSCFSet summary", "__NSCFSet", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "__CFSet summary", "__CFSet", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "__NSSetI summary", "__NSSetI", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "__NSSetM summary", "__NSSetM", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "NSCountedSet summary", "NSCountedSet", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "NSMutableSet summary", "NSMutableSet", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "NSOrderedSet summary", "NSOrderedSet", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "__NSOrderedSetI summary", "__NSOrderedSetI", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSSetSummaryProvider<false>,
+ "__NSOrderedSetM summary", "__NSOrderedSetM", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSError_SummaryProvider,
+ "NSError summary provider", "NSError", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSException_SummaryProvider,
+ "NSException summary provider", "NSException", appkit_flags);
+
+ // AddSummary(appkit_category_sp, "${var.key%@} -> ${var.value%@}",
+ // ConstString("$_lldb_typegen_nspair"), appkit_flags);
+
+ appkit_flags.SetDontShowChildren(true);
+
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "__NSArrayM",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "__NSArrayI",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "__NSArray0",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "__NSSingleObjectArrayI",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "NSArray",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "NSConstantArray",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "NSMutableArray",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "__NSCFArray",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "_NSCallStackArray",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "CFMutableArrayRef",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSArraySyntheticFrontEndCreator,
+ "NSArray synthetic children", "CFArrayRef",
+ ScriptedSyntheticChildren::Flags());
+
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "__NSDictionaryM",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "NSConstantDictionary",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "__NSDictionaryI",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "__NSSingleEntryDictionaryI",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "__NSCFDictionary",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "NSDictionary",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "NSMutableDictionary",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "CFDictionaryRef",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "CFMutableDictionaryRef",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(
+ objc_category_sp,
+ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator,
+ "NSDictionary synthetic children", "__CFDictionary",
+ ScriptedSyntheticChildren::Flags());
+
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSErrorSyntheticFrontEndCreator,
+ "NSError synthetic children", "NSError",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSExceptionSyntheticFrontEndCreator,
+ "NSException synthetic children", "NSException",
+ ScriptedSyntheticChildren::Flags());
+
+ AddCXXSynthetic(
+ objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "NSSet synthetic children", "NSSet", ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "__NSSetI synthetic children", "__NSSetI",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "__NSSetM synthetic children", "__NSSetM",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "__NSCFSet synthetic children", "__NSCFSet",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "CFSetRef synthetic children", "CFSetRef",
+ ScriptedSyntheticChildren::Flags());
+
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "NSMutableSet synthetic children", "NSMutableSet",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "NSOrderedSet synthetic children", "NSOrderedSet",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "__NSOrderedSetI synthetic children", "__NSOrderedSetI",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "__NSOrderedSetM synthetic children", "__NSOrderedSetM",
+ ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+ "__CFSet synthetic children", "__CFSet",
+ ScriptedSyntheticChildren::Flags());
+
+ AddCXXSynthetic(objc_category_sp,
+ lldb_private::formatters::NSIndexPathSyntheticFrontEndCreator,
+ "NSIndexPath synthetic children", "NSIndexPath",
+ ScriptedSyntheticChildren::Flags());
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::CFBagSummaryProvider,
+ "CFBag summary provider", "CFBagRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::CFBagSummaryProvider,
+ "CFBag summary provider", "__CFBag", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::CFBagSummaryProvider,
+ "CFBag summary provider", "const struct __CFBag", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::CFBagSummaryProvider,
+ "CFBag summary provider", "CFMutableBagRef", appkit_flags);
+
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::CFBinaryHeapSummaryProvider,
+ "CFBinaryHeap summary provider", "CFBinaryHeapRef", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::CFBinaryHeapSummaryProvider,
+ "CFBinaryHeap summary provider", "__CFBinaryHeap", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "NSString", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "CFStringRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "__CFString", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "CFMutableStringRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "NSMutableString", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "__NSCFConstantString", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "__NSCFString", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "NSCFConstantString", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "NSCFString", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "NSPathStore2", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSStringSummaryProvider,
+ "NSString summary provider", "NSTaggedPointerString", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSAttributedStringSummaryProvider,
+ "NSAttributedString summary provider", "NSAttributedString",
+ appkit_flags);
+ AddCXXSummary(
+ objc_category_sp,
+ lldb_private::formatters::NSMutableAttributedStringSummaryProvider,
+ "NSMutableAttributedString summary provider", "NSMutableAttributedString",
+ appkit_flags);
+ AddCXXSummary(
+ objc_category_sp,
+ lldb_private::formatters::NSMutableAttributedStringSummaryProvider,
+ "NSMutableAttributedString summary provider",
+ "NSConcreteMutableAttributedString", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSBundleSummaryProvider,
+ "NSBundle summary provider", "NSBundle", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDataSummaryProvider<false>,
+ "NSData summary provider", "NSData", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDataSummaryProvider<false>,
+ "NSData summary provider", "_NSInlineData", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDataSummaryProvider<false>,
+ "NSData summary provider", "NSConcreteData", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>,
+ "NSData summary provider", "NSConcreteMutableData", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDataSummaryProvider<false>,
+ "NSData summary provider", "NSMutableData", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDataSummaryProvider<false>,
+ "NSData summary provider", "__NSCFData", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDataSummaryProvider<true>,
+ "NSData summary provider", "CFDataRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDataSummaryProvider<true>,
+ "NSData summary provider", "CFMutableDataRef", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSMachPortSummaryProvider,
+ "NSMachPort summary provider", "NSMachPort", appkit_flags);
+
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSNotificationSummaryProvider,
+ "NSNotification summary provider", "NSNotification", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSNotificationSummaryProvider,
+ "NSNotification summary provider", "NSConcreteNotification",
+ appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSNumberSummaryProvider,
+ "NSNumber summary provider", "NSNumber", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
+ "NSNumber summary provider", "NSConstantIntegerNumber", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
+ "NSNumber summary provider", "NSConstantDoubleNumber", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
+ "NSNumber summary provider", "NSConstantFloatNumber", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSNumberSummaryProvider,
+ "CFNumberRef summary provider", "CFNumberRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSNumberSummaryProvider,
+ "NSNumber summary provider", "__NSCFBoolean", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSNumberSummaryProvider,
+ "NSNumber summary provider", "__NSCFNumber", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSNumberSummaryProvider,
+ "NSNumber summary provider", "NSCFBoolean", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSNumberSummaryProvider,
+ "NSNumber summary provider", "NSCFNumber", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider,
+ "NSDecimalNumber summary provider", "NSDecimalNumber", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSURLSummaryProvider,
+ "NSURL summary provider", "NSURL", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSURLSummaryProvider,
+ "NSURL summary provider", "CFURLRef", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDateSummaryProvider,
+ "NSDate summary provider", "NSDate", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDateSummaryProvider,
+ "NSDate summary provider", "__NSDate", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDateSummaryProvider,
+ "NSDate summary provider", "__NSTaggedDate", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSDateSummaryProvider,
+ "NSDate summary provider", "NSCalendarDate", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSTimeZoneSummaryProvider,
+ "NSTimeZone summary provider", "NSTimeZone", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSTimeZoneSummaryProvider,
+ "NSTimeZone summary provider", "CFTimeZoneRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSTimeZoneSummaryProvider,
+ "NSTimeZone summary provider", "__NSTimeZone", appkit_flags);
+
+ // CFAbsoluteTime is actually a double rather than a pointer to an object we
+ // do not care about the numeric value, since it is probably meaningless to
+ // users
+ appkit_flags.SetDontShowValue(true);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::CFAbsoluteTimeSummaryProvider,
+ "CFAbsoluteTime summary provider", "CFAbsoluteTime", appkit_flags);
+ appkit_flags.SetDontShowValue(false);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::NSIndexSetSummaryProvider,
+ "NSIndexSet summary provider", "NSIndexSet", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::NSIndexSetSummaryProvider,
+ "NSIndexSet summary provider", "NSMutableIndexSet", appkit_flags);
+
+ AddStringSummary(objc_category_sp,
+ "@\"${var.month%d}/${var.day%d}/${var.year%d} "
+ "${var.hour%d}:${var.minute%d}:${var.second}\"",
+ "CFGregorianDate", appkit_flags);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::CFBitVectorSummaryProvider,
+ "CFBitVector summary provider", "CFBitVectorRef", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider,
+ "CFBitVector summary provider", "CFMutableBitVectorRef", appkit_flags);
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::CFBitVectorSummaryProvider,
+ "CFBitVector summary provider", "__CFBitVector", appkit_flags);
+ AddCXXSummary(
+ objc_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider,
+ "CFBitVector summary provider", "__CFMutableBitVector", appkit_flags);
+}
+
+static void LoadCoreMediaFormatters(TypeCategoryImplSP objc_category_sp) {
+ if (!objc_category_sp)
+ return;
+
+ TypeSummaryImpl::Flags cm_flags;
+ cm_flags.SetCascades(true)
+ .SetDontShowChildren(false)
+ .SetDontShowValue(false)
+ .SetHideItemNames(false)
+ .SetShowMembersOneLiner(false)
+ .SetSkipPointers(false)
+ .SetSkipReferences(false);
+
+ AddCXXSummary(objc_category_sp,
+ lldb_private::formatters::CMTimeSummaryProvider,
+ "CMTime summary provider", "CMTime", cm_flags);
+}
+
+lldb::TypeCategoryImplSP ObjCLanguage::GetFormatters() {
+ static llvm::once_flag g_initialize;
+ static TypeCategoryImplSP g_category;
+
+ llvm::call_once(g_initialize, [this]() -> void {
+ DataVisualization::Categories::GetCategory(ConstString(GetPluginName()),
+ g_category);
+ if (g_category) {
+ LoadCoreMediaFormatters(g_category);
+ LoadObjCFormatters(g_category);
+ }
+ });
+ return g_category;
+}
+
+std::vector<FormattersMatchCandidate>
+ObjCLanguage::GetPossibleFormattersMatches(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) {
+ std::vector<FormattersMatchCandidate> result;
+
+ if (use_dynamic == lldb::eNoDynamicValues)
+ return result;
+
+ CompilerType compiler_type(valobj.GetCompilerType());
+
+ const bool check_cpp = false;
+ const bool check_objc = true;
+ bool canBeObjCDynamic =
+ compiler_type.IsPossibleDynamicType(nullptr, check_cpp, check_objc);
+
+ if (canBeObjCDynamic && ClangUtil::IsClangType(compiler_type)) {
+ do {
+ lldb::ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ break;
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
+ if (runtime == nullptr)
+ break;
+ ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp(
+ runtime->GetClassDescriptor(valobj));
+ if (!objc_class_sp)
+ break;
+ if (ConstString name = objc_class_sp->GetClassName())
+ result.push_back(
+ {name, valobj.GetTargetSP()->GetDebugger().GetScriptInterpreter(),
+ TypeImpl(objc_class_sp->GetType()),
+ FormattersMatchCandidate::Flags{}});
+ } while (false);
+ }
+
+ return result;
+}
+
+std::unique_ptr<Language::TypeScavenger> ObjCLanguage::GetTypeScavenger() {
+ class ObjCScavengerResult : public Language::TypeScavenger::Result {
+ public:
+ ObjCScavengerResult(CompilerType type)
+ : Language::TypeScavenger::Result(), m_compiler_type(type) {}
+
+ bool IsValid() override { return m_compiler_type.IsValid(); }
+
+ bool DumpToStream(Stream &stream, bool print_help_if_available) override {
+ if (IsValid()) {
+ m_compiler_type.DumpTypeDescription(&stream);
+ stream.EOL();
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ CompilerType m_compiler_type;
+ };
+
+ class ObjCRuntimeScavenger : public Language::TypeScavenger {
+ protected:
+ bool Find_Impl(ExecutionContextScope *exe_scope, const char *key,
+ ResultSet &results) override {
+ bool result = false;
+
+ if (auto *process = exe_scope->CalculateProcess().get()) {
+ if (auto *objc_runtime = ObjCLanguageRuntime::Get(*process)) {
+ if (auto *decl_vendor = objc_runtime->GetDeclVendor()) {
+ ConstString name(key);
+ for (const CompilerType &type :
+ decl_vendor->FindTypes(name, /*max_matches*/ UINT32_MAX)) {
+ result = true;
+ std::unique_ptr<Language::TypeScavenger::Result> result(
+ new ObjCScavengerResult(type));
+ results.insert(std::move(result));
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ friend class lldb_private::ObjCLanguage;
+ };
+
+ class ObjCModulesScavenger : public Language::TypeScavenger {
+ protected:
+ bool Find_Impl(ExecutionContextScope *exe_scope, const char *key,
+ ResultSet &results) override {
+ bool result = false;
+
+ if (auto *target = exe_scope->CalculateTarget().get()) {
+ auto *persistent_vars = llvm::cast<ClangPersistentVariables>(
+ target->GetPersistentExpressionStateForLanguage(
+ lldb::eLanguageTypeC));
+ if (std::shared_ptr<ClangModulesDeclVendor> clang_modules_decl_vendor =
+ persistent_vars->GetClangModulesDeclVendor()) {
+ ConstString key_cs(key);
+ auto types = clang_modules_decl_vendor->FindTypes(
+ key_cs, /*max_matches*/ UINT32_MAX);
+ if (!types.empty()) {
+ result = true;
+ std::unique_ptr<Language::TypeScavenger::Result> result(
+ new ObjCScavengerResult(types.front()));
+ results.insert(std::move(result));
+ }
+ }
+ }
+
+ return result;
+ }
+
+ friend class lldb_private::ObjCLanguage;
+ };
+
+ class ObjCDebugInfoScavenger : public Language::ImageListTypeScavenger {
+ public:
+ CompilerType AdjustForInclusion(CompilerType &candidate) override {
+ LanguageType lang_type(candidate.GetMinimumLanguage());
+ if (!Language::LanguageIsObjC(lang_type))
+ return CompilerType();
+ if (candidate.IsTypedefType())
+ return candidate.GetTypedefedType();
+ return candidate;
+ }
+ };
+
+ return std::unique_ptr<TypeScavenger>(
+ new Language::EitherTypeScavenger<ObjCModulesScavenger,
+ ObjCRuntimeScavenger,
+ ObjCDebugInfoScavenger>());
+}
+
+std::pair<llvm::StringRef, llvm::StringRef>
+ObjCLanguage::GetFormatterPrefixSuffix(llvm::StringRef type_hint) {
+ static constexpr llvm::StringRef empty;
+ static const llvm::StringMap<
+ std::pair<const llvm::StringRef, const llvm::StringRef>>
+ g_affix_map = {
+ {"CFBag", {"@", empty}},
+ {"CFBinaryHeap", {"@", empty}},
+ {"NSString", {"@", empty}},
+ {"NSString*", {"@", empty}},
+ {"NSNumber:char", {"(char)", empty}},
+ {"NSNumber:short", {"(short)", empty}},
+ {"NSNumber:int", {"(int)", empty}},
+ {"NSNumber:long", {"(long)", empty}},
+ {"NSNumber:int128_t", {"(int128_t)", empty}},
+ {"NSNumber:float", {"(float)", empty}},
+ {"NSNumber:double", {"(double)", empty}},
+ {"NSData", {"@\"", "\""}},
+ {"NSArray", {"@\"", "\""}},
+ };
+ return g_affix_map.lookup(type_hint);
+}
+
+bool ObjCLanguage::IsNilReference(ValueObject &valobj) {
+ const uint32_t mask = eTypeIsObjC | eTypeIsPointer;
+ bool isObjCpointer =
+ (((valobj.GetCompilerType().GetTypeInfo(nullptr)) & mask) == mask);
+ if (!isObjCpointer)
+ return false;
+ bool canReadValue = true;
+ bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
+ return canReadValue && isZero;
+}
+
+bool ObjCLanguage::IsSourceFile(llvm::StringRef file_path) const {
+ const auto suffixes = {".h", ".m", ".M"};
+ for (auto suffix : suffixes) {
+ if (file_path.ends_with_insensitive(suffix))
+ return true;
+ }
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
new file mode 100644
index 000000000000..d9c0cd3c18cf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
@@ -0,0 +1,205 @@
+//===-- ObjCLanguage.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H
+
+#include <cstring>
+#include <vector>
+
+#include "Plugins/Language/ClangCommon/ClangHighlighter.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class ObjCLanguage : public Language {
+ ClangHighlighter m_highlighter;
+
+public:
+ class MethodName {
+ public:
+ /// The static factory method for creating a MethodName.
+ ///
+ /// \param[in] name
+ /// The name of the method.
+ ///
+ /// \param[in] strict
+ /// Control whether or not the name parser is strict about +/- in the
+ /// front of the name.
+ ///
+ /// \return If the name failed to parse as a valid Objective-C method name,
+ /// returns std::nullopt. Otherwise returns a const MethodName.
+ static std::optional<const MethodName> Create(llvm::StringRef name,
+ bool strict);
+
+ /// Determines if this method is a class method
+ ///
+ /// \return Returns true if the method is a class method. False otherwise.
+ bool IsClassMethod() const { return m_type == eTypeClassMethod; }
+
+ /// Determines if this method is an instance method
+ ///
+ /// \return Returns true if the method is an instance method. False
+ /// otherwise.
+ bool IsInstanceMethod() const { return m_type == eTypeInstanceMethod; }
+
+ /// Returns the full name of the method.
+ ///
+ /// This includes the class name, the category name (if applicable), and the
+ /// selector name.
+ ///
+ /// \return The name of the method in the form of a const std::string
+ /// reference.
+ const std::string &GetFullName() const { return m_full; }
+
+ /// Creates a variation of this method without the category.
+ /// If this method has no category, it returns an empty string.
+ ///
+ /// Example:
+ /// Full name: "+[NSString(my_additions) myStringWithCString:]"
+ /// becomes "+[NSString myStringWithCString:]"
+ ///
+ /// \return The method name without the category or an empty string if there
+ /// was no category to begin with.
+ std::string GetFullNameWithoutCategory() const;
+
+ /// Returns a reference to the class name.
+ ///
+ /// Example:
+ /// Full name: "+[NSString(my_additions) myStringWithCString:]"
+ /// will give you "NSString"
+ ///
+ /// \return A StringRef to the class name of this method.
+ llvm::StringRef GetClassName() const;
+
+ /// Returns a reference to the class name with the category.
+ ///
+ /// Example:
+ /// Full name: "+[NSString(my_additions) myStringWithCString:]"
+ /// will give you "NSString(my_additions)"
+ ///
+ /// Note: If your method has no category, this will give the same output as
+ /// `GetClassName`.
+ ///
+ /// \return A StringRef to the class name (including the category) of this
+ /// method. If there was no category, returns the same as `GetClassName`.
+ llvm::StringRef GetClassNameWithCategory() const;
+
+ /// Returns a reference to the category name.
+ ///
+ /// Example:
+ /// Full name: "+[NSString(my_additions) myStringWithCString:]"
+ /// will give you "my_additions"
+ /// \return A StringRef to the category name of this method. If no category
+ /// is present, the StringRef is empty.
+ llvm::StringRef GetCategory() const;
+
+ /// Returns a reference to the selector name.
+ ///
+ /// Example:
+ /// Full name: "+[NSString(my_additions) myStringWithCString:]"
+ /// will give you "myStringWithCString:"
+ /// \return A StringRef to the selector of this method.
+ llvm::StringRef GetSelector() const;
+
+ protected:
+ enum Type { eTypeUnspecified, eTypeClassMethod, eTypeInstanceMethod };
+
+ MethodName(llvm::StringRef name, Type type)
+ : m_full(name.str()), m_type(type) {}
+
+ const std::string m_full;
+ Type m_type;
+ };
+
+ ObjCLanguage() = default;
+
+ ~ObjCLanguage() override = default;
+
+ lldb::LanguageType GetLanguageType() const override {
+ return lldb::eLanguageTypeObjC;
+ }
+
+ llvm::StringRef GetUserEntryPointName() const override { return "main"; }
+
+ // Get all possible names for a method. Examples:
+ // If method_name is "+[NSString(my_additions) myStringWithCString:]"
+ // variant_names[0] => "+[NSString myStringWithCString:]"
+ // If name is specified without the leading '+' or '-' like
+ // "[NSString(my_additions) myStringWithCString:]"
+ // variant_names[0] => "+[NSString(my_additions) myStringWithCString:]"
+ // variant_names[1] => "-[NSString(my_additions) myStringWithCString:]"
+ // variant_names[2] => "+[NSString myStringWithCString:]"
+ // variant_names[3] => "-[NSString myStringWithCString:]"
+ // Also returns the FunctionNameType of each possible name.
+ std::vector<Language::MethodNameVariant>
+ GetMethodNameVariants(ConstString method_name) const override;
+
+ bool SymbolNameFitsToLanguage(Mangled mangled) const override;
+
+ lldb::TypeCategoryImplSP GetFormatters() override;
+
+ std::vector<FormattersMatchCandidate>
+ GetPossibleFormattersMatches(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) override;
+
+ std::unique_ptr<TypeScavenger> GetTypeScavenger() override;
+
+ std::pair<llvm::StringRef, llvm::StringRef>
+ GetFormatterPrefixSuffix(llvm::StringRef type_hint) override;
+
+ bool IsNilReference(ValueObject &valobj) override;
+
+ llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; }
+
+ bool IsSourceFile(llvm::StringRef file_path) const override;
+
+ const Highlighter *GetHighlighter() const override { return &m_highlighter; }
+
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static lldb_private::Language *CreateInstance(lldb::LanguageType language);
+
+ static llvm::StringRef GetPluginNameStatic() { return "objc"; }
+
+ static bool IsPossibleObjCMethodName(const char *name) {
+ if (!name)
+ return false;
+ bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '[';
+ bool ends_right = (name[strlen(name) - 1] == ']');
+ return (starts_right && ends_right);
+ }
+
+ static bool IsPossibleObjCSelector(const char *name) {
+ if (!name)
+ return false;
+
+ if (strchr(name, ':') == nullptr)
+ return true;
+ else if (name[strlen(name) - 1] == ':')
+ return true;
+ else
+ return false;
+ }
+
+ llvm::StringRef GetInstanceVariableName() override { return "self"; }
+
+ bool SupportsExceptionBreakpointsOnThrow() const override { return true; }
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_OBJCLANGUAGE_H