[Lldb-commits] [lldb] 28fb39f - [lldb] Adjust for changes in objc runtime
Alex Langford via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 22 16:49:23 PDT 2023
Author: Alex Langford
Date: 2023-06-22T16:42:22-07:00
New Revision: 28fb39f16af1003e53008b75c11127b3288742f8
URL: https://github.com/llvm/llvm-project/commit/28fb39f16af1003e53008b75c11127b3288742f8
DIFF: https://github.com/llvm/llvm-project/commit/28fb39f16af1003e53008b75c11127b3288742f8.diff
LOG: [lldb] Adjust for changes in objc runtime
The Objective-C runtime and the shared cache has changed slightly.
Given a class_ro_t, the baseMethods ivar is now a pointer union and may
either be a method_list_t pointer or a pointer to a relative list of
lists. The entries of this relative list of lists are indexes that refer
to a specific image in the shared cache in addition to a pointer offset
to find the accompanying method_list_t. We have to go over each of these
entries, parse it, and then if the relevant image is loaded in the
process, we add those methods to the relevant clang Decl.
In order to determine if an image is loaded, the Objective-C runtime
exposes a symbol that lets us determine if a particular image is loaded.
We maintain a data structure SharedCacheImageHeaders to keep track of
that information.
There is a known issue where if an image is loaded after we create a
Decl for a class, the Decl will not have the relevant methods from that
image (i.e. for Categories).
rdar://107957209
Differential Revision: https://reviews.llvm.org/D153597
Added:
Modified:
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
lldb/test/API/lang/objc/exceptions/TestObjCExceptions.py
Removed:
################################################################################
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
index 438842db4eec5..80ba352228c54 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
@@ -370,6 +370,155 @@ bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) {
return !error.Fail();
}
+bool ClassDescriptorV2::relative_list_entry_t::Read(Process *process,
+ lldb::addr_t addr) {
+ Log *log = GetLog(LLDBLog::Types);
+ size_t size = sizeof(uint64_t); // m_image_index : 16
+ // m_list_offset : 48
+
+ DataBufferHeap buffer(size, '\0');
+ Status error;
+
+ process->ReadMemory(addr, buffer.GetBytes(), size, error);
+ // FIXME: Propagate this error up
+ if (error.Fail()) {
+ LLDB_LOG(log, "Failed to read relative_list_entry_t at address {0:x}",
+ addr);
+ return false;
+ }
+
+ DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
+ process->GetAddressByteSize());
+ lldb::offset_t cursor = 0;
+ uint64_t raw_entry = extractor.GetU64_unchecked(&cursor);
+ m_image_index = raw_entry & 0xFFFF;
+ m_list_offset = (int64_t)(raw_entry >> 16);
+ return true;
+}
+
+bool ClassDescriptorV2::relative_list_list_t::Read(Process *process,
+ lldb::addr_t addr) {
+ Log *log = GetLog(LLDBLog::Types);
+ size_t size = sizeof(uint32_t) // m_entsize
+ + sizeof(uint32_t); // m_count
+
+ DataBufferHeap buffer(size, '\0');
+ Status error;
+
+ // FIXME: Propagate this error up
+ process->ReadMemory(addr, buffer.GetBytes(), size, error);
+ if (error.Fail()) {
+ LLDB_LOG(log, "Failed to read relative_list_list_t at address 0x" PRIx64,
+ addr);
+ return false;
+ }
+
+ DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
+ process->GetAddressByteSize());
+ lldb::offset_t cursor = 0;
+ m_entsize = extractor.GetU32_unchecked(&cursor);
+ m_count = extractor.GetU32_unchecked(&cursor);
+ m_first_ptr = addr + cursor;
+ return true;
+}
+
+std::optional<ClassDescriptorV2::method_list_t>
+ClassDescriptorV2::GetMethodList(Process *process,
+ lldb::addr_t method_list_ptr) const {
+ Log *log = GetLog(LLDBLog::Types);
+ ClassDescriptorV2::method_list_t method_list;
+ if (!method_list.Read(process, method_list_ptr))
+ return std::nullopt;
+
+ const size_t method_size = method_t::GetSize(process, method_list.m_is_small);
+ if (method_list.m_entsize != method_size) {
+ LLDB_LOG(log,
+ "method_list_t at address 0x" PRIx64 " has an entsize of " PRIu16
+ " but method size should be " PRIu64,
+ method_list_ptr, method_list.m_entsize, method_size);
+ return std::nullopt;
+ }
+
+ return method_list;
+}
+
+bool ClassDescriptorV2::ProcessMethodList(
+ std::function<bool(const char *, const char *)> const &instance_method_func,
+ ClassDescriptorV2::method_list_t &method_list) const {
+ lldb_private::Process *process = m_runtime.GetProcess();
+ auto method = std::make_unique<method_t>();
+ lldb::addr_t relative_selector_base_addr =
+ m_runtime.GetRelativeSelectorBaseAddr();
+ for (uint32_t i = 0, e = method_list.m_count; i < e; ++i) {
+ method->Read(process, method_list.m_first_ptr + (i * method_list.m_entsize),
+ relative_selector_base_addr, method_list.m_is_small,
+ method_list.m_has_direct_selector);
+ if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
+ break;
+ }
+ return true;
+}
+
+// The relevant data structures:
+// - relative_list_list_t
+// - uint32_t count
+// - uint32_t entsize
+// - Followed by <count> number of relative_list_entry_t of size <entsize>
+//
+// - relative_list_entry_t
+// - uint64_t image_index : 16
+// - int64_t list_offset : 48
+// - Note: The above 2 fit into 8 bytes always
+//
+// image_index corresponds to an image in the shared cache
+// list_offset is used to calculate the address of the method_list_t we want
+bool ClassDescriptorV2::ProcessRelativeMethodLists(
+ std::function<bool(const char *, const char *)> const &instance_method_func,
+ lldb::addr_t relative_method_list_ptr) const {
+ lldb_private::Process *process = m_runtime.GetProcess();
+ auto relative_method_lists = std::make_unique<relative_list_list_t>();
+
+ // 1. Process the count and entsize of the relative_list_list_t
+ if (!relative_method_lists->Read(process, relative_method_list_ptr))
+ return false;
+
+ auto entry = std::make_unique<relative_list_entry_t>();
+ for (uint32_t i = 0; i < relative_method_lists->m_count; i++) {
+ // 2. Extract the image index and the list offset from the
+ // relative_list_entry_t
+ const lldb::addr_t entry_addr = relative_method_lists->m_first_ptr +
+ (i * relative_method_lists->m_entsize);
+ if (!entry->Read(process, entry_addr))
+ return false;
+
+ // 3. Calculate the pointer to the method_list_t from the
+ // relative_list_entry_t
+ const lldb::addr_t method_list_addr = entry_addr + entry->m_list_offset;
+
+ // 4. Get the method_list_t from the pointer
+ std::optional<method_list_t> method_list =
+ GetMethodList(process, method_list_addr);
+ if (!method_list)
+ return false;
+
+ // 5. Cache the result so we don't need to reconstruct it later.
+ m_image_to_method_lists[entry->m_image_index].emplace_back(*method_list);
+
+ // 6. If the relevant image is loaded, add the methods to the Decl
+ if (!m_runtime.IsSharedCacheImageLoaded(entry->m_image_index))
+ continue;
+
+ if (!ProcessMethodList(instance_method_func, *method_list))
+ return false;
+ }
+
+ // We need to keep track of the last time we updated so we can re-update the
+ // type information in the future
+ m_last_version_updated = m_runtime.GetSharedCacheImageHeaderVersion();
+
+ return true;
+}
+
bool ClassDescriptorV2::Describe(
std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
std::function<bool(const char *, const char *)> const &instance_method_func,
@@ -393,29 +542,18 @@ bool ClassDescriptorV2::Describe(
superclass_func(objc_class->m_superclass);
if (instance_method_func) {
- std::unique_ptr<method_list_t> base_method_list;
-
- base_method_list = std::make_unique<method_list_t>();
- if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr))
- return false;
-
- bool is_small = base_method_list->m_is_small;
- bool has_direct_selector = base_method_list->m_has_direct_selector;
-
- if (base_method_list->m_entsize != method_t::GetSize(process, is_small))
- return false;
-
- std::unique_ptr<method_t> method = std::make_unique<method_t>();
- lldb::addr_t relative_selector_base_addr =
- m_runtime.GetRelativeSelectorBaseAddr();
- for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) {
- method->Read(process,
- base_method_list->m_first_ptr +
- (i * base_method_list->m_entsize),
- relative_selector_base_addr, is_small, has_direct_selector);
-
- if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
- break;
+ // This is a relative list of lists
+ if (class_ro->m_baseMethods_ptr & 1) {
+ if (!ProcessRelativeMethodLists(instance_method_func,
+ class_ro->m_baseMethods_ptr ^ 1))
+ return false;
+ } else {
+ std::optional<method_list_t> base_method_list =
+ GetMethodList(process, class_ro->m_baseMethods_ptr);
+ if (!base_method_list)
+ return false;
+ if (!ProcessMethodList(instance_method_func, *base_method_list))
+ return false;
}
}
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
index 0c6eccab9f27c..09e5383d7fb95 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
@@ -146,6 +146,9 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
bool Read(Process *process, lldb::addr_t addr);
};
+ std::optional<method_list_t>
+ GetMethodList(Process *process, lldb::addr_t method_list_ptr) const;
+
struct method_t {
lldb::addr_t m_name_ptr;
lldb::addr_t m_types_ptr;
@@ -201,6 +204,21 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
bool Read(Process *process, lldb::addr_t addr);
};
+ struct relative_list_entry_t {
+ uint16_t m_image_index;
+ int64_t m_list_offset;
+
+ bool Read(Process *process, lldb::addr_t addr);
+ };
+
+ struct relative_list_list_t {
+ uint32_t m_entsize;
+ uint32_t m_count;
+ lldb::addr_t m_first_ptr;
+
+ bool Read(Process *process, lldb::addr_t addr);
+ };
+
class iVarsStorage {
public:
iVarsStorage();
@@ -223,7 +241,8 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
ClassDescriptorV2(AppleObjCRuntimeV2 &runtime,
ObjCLanguageRuntime::ObjCISA isa, const char *name)
: m_runtime(runtime), m_objc_class_ptr(isa), m_name(name),
- m_ivars_storage() {}
+ m_ivars_storage(), m_image_to_method_lists(), m_last_version_updated() {
+ }
bool Read_objc_class(Process *process,
std::unique_ptr<objc_class_t> &objc_class) const;
@@ -232,6 +251,15 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
std::unique_ptr<class_ro_t> &class_ro,
std::unique_ptr<class_rw_t> &class_rw) const;
+ bool ProcessMethodList(std::function<bool(const char *, const char *)> const
+ &instance_method_func,
+ method_list_t &method_list) const;
+
+ bool ProcessRelativeMethodLists(
+ std::function<bool(const char *, const char *)> const
+ &instance_method_func,
+ lldb::addr_t relative_method_list_ptr) const;
+
AppleObjCRuntimeV2
&m_runtime; // The runtime, so we can read information lazily.
lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e.,
@@ -239,6 +267,10 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
// their ISA)
ConstString m_name; // May be NULL
iVarsStorage m_ivars_storage;
+
+ mutable std::map<uint16_t, std::vector<method_list_t>>
+ m_image_to_method_lists;
+ mutable std::optional<uint64_t> m_last_version_updated;
};
// tagged pointer descriptor
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index cd34d7899db84..fc9b4d27ccb66 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -1619,6 +1619,146 @@ lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() {
return m_isa_hash_table_ptr;
}
+std::unique_ptr<AppleObjCRuntimeV2::SharedCacheImageHeaders>
+AppleObjCRuntimeV2::SharedCacheImageHeaders::CreateSharedCacheImageHeaders(
+ AppleObjCRuntimeV2 &runtime) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
+ Process *process = runtime.GetProcess();
+ ModuleSP objc_module_sp(runtime.GetObjCModule());
+ if (!objc_module_sp || !process)
+ return nullptr;
+
+ const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
+ ConstString("objc_debug_headerInfoRWs"), lldb::eSymbolTypeAny);
+ if (!symbol) {
+ LLDB_LOG(log, "Symbol 'objc_debug_headerInfoRWs' unavailable. Some "
+ "information concerning the shared cache may be unavailable");
+ return nullptr;
+ }
+
+ lldb::addr_t objc_debug_headerInfoRWs_addr =
+ symbol->GetLoadAddress(&process->GetTarget());
+ if (objc_debug_headerInfoRWs_addr == LLDB_INVALID_ADDRESS) {
+ LLDB_LOG(log, "Symbol 'objc_debug_headerInfoRWs' was found but we were "
+ "unable to get its load address");
+ return nullptr;
+ }
+
+ Status error;
+ lldb::addr_t objc_debug_headerInfoRWs_ptr =
+ process->ReadPointerFromMemory(objc_debug_headerInfoRWs_addr, error);
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "Failed to read address of 'objc_debug_headerInfoRWs' at {0:x}",
+ objc_debug_headerInfoRWs_addr);
+ return nullptr;
+ }
+
+ const size_t metadata_size =
+ sizeof(uint32_t) + sizeof(uint32_t); // count + entsize
+ DataBufferHeap metadata_buffer(metadata_size, '\0');
+ process->ReadMemory(objc_debug_headerInfoRWs_ptr, metadata_buffer.GetBytes(),
+ metadata_size, error);
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "Unable to read metadata for 'objc_debug_headerInfoRWs' at {0:x}",
+ objc_debug_headerInfoRWs_ptr);
+ return nullptr;
+ }
+
+ DataExtractor metadata_extractor(metadata_buffer.GetBytes(), metadata_size,
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ lldb::offset_t cursor = 0;
+ uint32_t count = metadata_extractor.GetU32_unchecked(&cursor);
+ uint32_t entsize = metadata_extractor.GetU32_unchecked(&cursor);
+ if (count == 0 || entsize == 0) {
+ LLDB_LOG(log,
+ "'objc_debug_headerInfoRWs' had count {0} with entsize {1}. These "
+ "should both be non-zero.",
+ count, entsize);
+ return nullptr;
+ }
+
+ std::unique_ptr<SharedCacheImageHeaders> shared_cache_image_headers(
+ new SharedCacheImageHeaders(runtime, objc_debug_headerInfoRWs_ptr, count,
+ entsize));
+ if (auto Err = shared_cache_image_headers->UpdateIfNeeded()) {
+ LLDB_LOG_ERROR(log, std::move(Err),
+ "Failed to update SharedCacheImageHeaders");
+ return nullptr;
+ }
+
+ return shared_cache_image_headers;
+}
+
+llvm::Error AppleObjCRuntimeV2::SharedCacheImageHeaders::UpdateIfNeeded() {
+ if (!m_needs_update)
+ return llvm::Error::success();
+
+ Process *process = m_runtime.GetProcess();
+ constexpr lldb::addr_t metadata_size =
+ sizeof(uint32_t) + sizeof(uint32_t); // count + entsize
+
+ Status error;
+ const lldb::addr_t first_header_addr = m_headerInfoRWs_ptr + metadata_size;
+ DataBufferHeap header_buffer(m_entsize, '\0');
+ lldb::offset_t cursor = 0;
+ for (uint32_t i = 0; i < m_count; i++) {
+ const lldb::addr_t header_addr = first_header_addr + (i * m_entsize);
+ process->ReadMemory(header_addr, header_buffer.GetBytes(), m_entsize,
+ error);
+ if (error.Fail())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Failed to read memory from inferior when "
+ "populating SharedCacheImageHeaders");
+
+ DataExtractor header_extractor(header_buffer.GetBytes(), m_entsize,
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ cursor = 0;
+ bool is_loaded = false;
+ if (m_entsize == 4) {
+ uint32_t header = header_extractor.GetU32_unchecked(&cursor);
+ if (header & 1)
+ is_loaded = true;
+ } else {
+ uint64_t header = header_extractor.GetU64_unchecked(&cursor);
+ if (header & 1)
+ is_loaded = true;
+ }
+
+ if (is_loaded)
+ m_loaded_images.set(i);
+ else
+ m_loaded_images.reset(i);
+ }
+ m_needs_update = false;
+ m_version++;
+ return llvm::Error::success();
+}
+
+bool AppleObjCRuntimeV2::SharedCacheImageHeaders::IsImageLoaded(
+ uint16_t image_index) {
+ if (image_index >= m_count)
+ return false;
+ if (auto Err = UpdateIfNeeded()) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
+ LLDB_LOG_ERROR(log, std::move(Err),
+ "Failed to update SharedCacheImageHeaders");
+ }
+ return m_loaded_images.test(image_index);
+}
+
+uint64_t AppleObjCRuntimeV2::SharedCacheImageHeaders::GetVersion() {
+ if (auto Err = UpdateIfNeeded()) {
+ Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
+ LLDB_LOG_ERROR(log, std::move(Err),
+ "Failed to update SharedCacheImageHeaders");
+ }
+ return m_version;
+}
+
std::unique_ptr<UtilityFunction>
AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunctionImpl(
ExecutionContext &exe_ctx, Helper helper, std::string code,
@@ -3239,6 +3379,34 @@ void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false);
}
+void AppleObjCRuntimeV2::ModulesDidLoad(const ModuleList &module_list) {
+ AppleObjCRuntime::ModulesDidLoad(module_list);
+ if (HasReadObjCLibrary() && m_shared_cache_image_headers_up)
+ m_shared_cache_image_headers_up->SetNeedsUpdate();
+}
+
+bool AppleObjCRuntimeV2::IsSharedCacheImageLoaded(uint16_t image_index) {
+ if (!m_shared_cache_image_headers_up) {
+ m_shared_cache_image_headers_up =
+ SharedCacheImageHeaders::CreateSharedCacheImageHeaders(*this);
+ }
+ if (m_shared_cache_image_headers_up)
+ return m_shared_cache_image_headers_up->IsImageLoaded(image_index);
+
+ return false;
+}
+
+std::optional<uint64_t> AppleObjCRuntimeV2::GetSharedCacheImageHeaderVersion() {
+ if (!m_shared_cache_image_headers_up) {
+ m_shared_cache_image_headers_up =
+ SharedCacheImageHeaders::CreateSharedCacheImageHeaders(*this);
+ }
+ if (m_shared_cache_image_headers_up)
+ return m_shared_cache_image_headers_up->GetVersion();
+
+ return std::nullopt;
+}
+
#pragma mark Frame recognizers
class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame {
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
index 95a3694c64b00..da30d8135f6d4 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -19,6 +19,8 @@
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "llvm/ADT/BitVector.h"
+
class RemoteNXMapTable;
namespace lldb_private {
@@ -96,6 +98,12 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
lldb::addr_t &cf_false) override;
+ void ModulesDidLoad(const ModuleList &module_list) override;
+
+ bool IsSharedCacheImageLoaded(uint16_t image_index);
+
+ std::optional<uint64_t> GetSharedCacheImageHeaderVersion();
+
protected:
lldb::BreakpointResolverSP
CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
@@ -374,6 +382,35 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
lldb::addr_t m_args = LLDB_INVALID_ADDRESS;
};
+ class SharedCacheImageHeaders {
+ public:
+ static std::unique_ptr<SharedCacheImageHeaders>
+ CreateSharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime);
+
+ void SetNeedsUpdate() { m_needs_update = true; }
+
+ bool IsImageLoaded(uint16_t image_index);
+
+ uint64_t GetVersion();
+
+ private:
+ SharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime,
+ lldb::addr_t headerInfoRWs_ptr, uint32_t count,
+ uint32_t entsize)
+ : m_runtime(runtime), m_headerInfoRWs_ptr(headerInfoRWs_ptr),
+ m_loaded_images(count, false), m_version(0), m_count(count),
+ m_entsize(entsize), m_needs_update(true) {}
+ llvm::Error UpdateIfNeeded();
+
+ AppleObjCRuntimeV2 &m_runtime;
+ lldb::addr_t m_headerInfoRWs_ptr;
+ llvm::BitVector m_loaded_images;
+ uint64_t m_version;
+ uint32_t m_count;
+ uint32_t m_entsize;
+ bool m_needs_update;
+ };
+
AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp);
ObjCISA GetPointerISA(ObjCISA isa);
@@ -435,6 +472,7 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
std::once_flag m_no_expanded_cache_warning;
std::optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values;
uint64_t m_realized_class_generation_count;
+ std::unique_ptr<SharedCacheImageHeaders> m_shared_cache_image_headers_up;
};
} // namespace lldb_private
diff --git a/lldb/test/API/lang/objc/exceptions/TestObjCExceptions.py b/lldb/test/API/lang/objc/exceptions/TestObjCExceptions.py
index 852cdf7d0737d..3763fa4f4a492 100644
--- a/lldb/test/API/lang/objc/exceptions/TestObjCExceptions.py
+++ b/lldb/test/API/lang/objc/exceptions/TestObjCExceptions.py
@@ -87,7 +87,6 @@ def test_objc_exceptions_at_throw(self):
"userInfo = ",
"1 key/value pair",
"reserved = ",
- "nil",
],
)
@@ -105,7 +104,6 @@ def test_objc_exceptions_at_throw(self):
self.assertEqual(
userInfo.GetChildAtIndex(0).GetChildAtIndex(1).description, "some_value"
)
- self.assertEqual(e1.GetChildMemberWithName("reserved").description, "<nil>")
self.expect(
"frame variable e2", substrs=["(NSException *) e2 = ", '"SomeReason"']
More information about the lldb-commits
mailing list