[Lldb-commits] [lldb] fc71a5c - [lldb] Support new objective-c hash table layout
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Fri Jun 11 10:26:21 PDT 2021
Author: Jonas Devlieghere
Date: 2021-06-11T10:26:16-07:00
New Revision: fc71a5c6e8e8bd28e43cf58faabad6e7e2fcc652
URL: https://github.com/llvm/llvm-project/commit/fc71a5c6e8e8bd28e43cf58faabad6e7e2fcc652
DIFF: https://github.com/llvm/llvm-project/commit/fc71a5c6e8e8bd28e43cf58faabad6e7e2fcc652.diff
LOG: [lldb] Support new objective-c hash table layout
Update LLDB for thew new Objective-C hash table layout in the dyld
shared cache found in macOS Monterey.
rdar://72863911
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
Removed:
################################################################################
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
index c1082100f2746..405b8a6f16b77 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
@@ -252,6 +252,7 @@ bool ClassDescriptorV2::method_list_t::Read(Process *process,
}
bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr,
+ lldb::addr_t relative_selector_base_addr,
bool is_small, bool has_direct_sel) {
size_t ptr_size = process->GetAddressByteSize();
size_t size = GetSize(process, is_small);
@@ -281,6 +282,8 @@ bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr,
0, error);
if (!error.Success())
return false;
+ } else if (relative_selector_base_addr != LLDB_INVALID_ADDRESS) {
+ m_name_ptr = relative_selector_base_addr + nameref_offset;
}
m_types_ptr = addr + 4 + types_offset;
m_imp_ptr = addr + 8 + imp_offset;
@@ -389,14 +392,14 @@ bool ClassDescriptorV2::Describe(
if (base_method_list->m_entsize != method_t::GetSize(process, is_small))
return false;
- std::unique_ptr<method_t> method;
- method = std::make_unique<method_t>();
-
+ 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),
- is_small, has_direct_selector);
+ relative_selector_base_addr, is_small, has_direct_selector);
if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
break;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
index 16e94f6790841..60374498c8965 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
@@ -166,7 +166,8 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
+ field_size; // IMP imp;
}
- bool Read(Process *process, lldb::addr_t addr, bool, bool);
+ bool Read(Process *process, lldb::addr_t addr,
+ lldb::addr_t relative_method_lists_base_addr, bool, bool);
};
struct ivar_list_t {
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 83f4356c3fb37..069368c8e058b 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -263,6 +263,12 @@ struct objc_classheader_t {
int32_t hiOffset;
};
+struct objc_classheader_v16_t {
+ uint64_t isDuplicate : 1,
+ objectCacheOffset : 47, // Offset from the shared cache base
+ dylibObjCIndex : 16;
+};
+
struct objc_clsopt_t {
uint32_t capacity;
uint32_t occupied;
@@ -280,6 +286,22 @@ struct objc_clsopt_t {
// objc_classheader_t duplicateOffsets[duplicateCount];
};
+struct objc_clsopt_v16_t {
+ uint32_t version;
+ uint32_t capacity;
+ uint32_t occupied;
+ uint32_t shift;
+ uint32_t mask;
+ uint64_t salt;
+ uint32_t scramble[256];
+ uint8_t tab[0]; // tab[mask+1]
+ // uint8_t checkbytes[capacity];
+ // int32_t offset[capacity];
+ // objc_classheader_t clsOffsets[capacity];
+ // uint32_t duplicateCount;
+ // objc_classheader_t duplicateOffsets[duplicateCount];
+};
+
struct objc_opt_t {
uint32_t version;
int32_t selopt_offset;
@@ -295,6 +317,20 @@ struct objc_opt_v14_t {
int32_t clsopt_offset;
};
+struct objc_opt_v16_t {
+ uint32_t version;
+ uint32_t flags;
+ int32_t selopt_offset;
+ int32_t headeropt_ro_offset;
+ int32_t unused_clsopt_offset;
+ int32_t unused_protocolopt_offset;
+ int32_t headeropt_rw_offset;
+ int32_t unused_protocolopt2_offset;
+ int32_t largeSharedCachesClassOffset;
+ int32_t largeSharedCachesProtocolOffset;
+ uint64_t relativeMethodSelectorBaseAddressCacheOffset;
+};
+
struct ClassInfo
{
Class isa;
@@ -303,19 +339,33 @@ struct ClassInfo
uint32_t
__lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
+ void *shared_cache_base_ptr,
void *class_infos_ptr,
+ uint64_t *relative_selector_offset,
uint32_t class_infos_byte_size,
uint32_t should_log)
{
+ *relative_selector_offset = 0;
uint32_t idx = 0;
DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);
+ DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr);
DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));
if (objc_opt_ro_ptr)
{
const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
const objc_opt_v14_t* objc_opt_v14 = (objc_opt_v14_t*)objc_opt_ro_ptr;
- if (objc_opt->version >= 14)
+ const objc_opt_v16_t* objc_opt_v16 = (objc_opt_v16_t*)objc_opt_ro_ptr;
+ if (objc_opt->version >= 16)
+ {
+ *relative_selector_offset = objc_opt_v16->relativeMethodSelectorBaseAddressCacheOffset;
+ DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v16->version);
+ DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v16->flags);
+ DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v16->selopt_offset);
+ DEBUG_PRINTF ("objc_opt->headeropt_ro_offset = %d\n", objc_opt_v16->headeropt_ro_offset);
+ DEBUG_PRINTF ("objc_opt->relativeMethodSelectorBaseAddressCacheOffset = %d\n", *relative_selector_offset);
+ }
+ else if (objc_opt->version >= 14)
{
DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v14->version);
DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v14->flags);
@@ -330,7 +380,123 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);
DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);
}
- if (objc_opt->version == 12 || objc_opt->version == 13 || objc_opt->version == 14 || objc_opt->version == 15)
+
+ if (objc_opt->version == 16)
+ {
+ const objc_clsopt_v16_t* clsopt = (const objc_clsopt_v16_t*)((uint8_t *)objc_opt + objc_opt_v16->largeSharedCachesClassOffset);
+ const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
+
+ DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);
+
+ ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
+
+ const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
+ const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
+ const objc_classheader_v16_t *classOffsets = (const objc_classheader_v16_t *)(offsets + clsopt->capacity);
+
+ DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
+ DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
+ DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
+
+ for (uint32_t i=0; i<clsopt->capacity; ++i)
+ {
+ const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
+ DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
+
+ if (classOffsets[i].isDuplicate) {
+ DEBUG_PRINTF("isDuplicate = true\n");
+ continue; // duplicate
+ }
+
+ if (objectCacheOffset == 0) {
+ DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
+ continue; // invalid offset
+ }
+
+ if (class_infos && idx < max_class_infos)
+ {
+ class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
+
+ // Lookup the class name.
+ const char *name = class_name_lookup_func(class_infos[idx].isa);
+ DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+
+ // Hash the class name so we don't have to read it.
+ const char *s = name;
+ uint32_t h = 5381;
+ for (unsigned char c = *s; c; c = *++s)
+ {
+ // class_getName demangles swift names and the hash must
+ // be calculated on the mangled name. hash==0 means lldb
+ // will fetch the mangled name and compute the hash in
+ // ParseClassInfoArray.
+ if (c == '.')
+ {
+ h = 0;
+ break;
+ }
+ h = ((h << 5) + h) + c;
+ }
+ class_infos[idx].hash = h;
+ }
+ else
+ {
+ DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
+ }
+ ++idx;
+ }
+
+ const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
+ const uint32_t duplicate_count = *duplicate_count_ptr;
+ const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
+
+ DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
+ DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
+
+ for (uint32_t i=0; i<duplicate_count; ++i)
+ {
+ const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
+ DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
+
+ if (classOffsets[i].isDuplicate) {
+ DEBUG_PRINTF("isDuplicate = true\n");
+ continue; // duplicate
+ }
+
+ if (objectCacheOffset == 0) {
+ DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
+ continue; // invalid offset
+ }
+
+ if (class_infos && idx < max_class_infos)
+ {
+ class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
+
+ // Lookup the class name.
+ const char *name = class_name_lookup_func(class_infos[idx].isa);
+ DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+
+ // Hash the class name so we don't have to read it.
+ const char *s = name;
+ uint32_t h = 5381;
+ for (unsigned char c = *s; c; c = *++s)
+ {
+ // class_getName demangles swift names and the hash must
+ // be calculated on the mangled name. hash==0 means lldb
+ // will fetch the mangled name and compute the hash in
+ // ParseClassInfoArray.
+ if (c == '.')
+ {
+ h = 0;
+ break;
+ }
+ h = ((h << 5) + h) + c;
+ }
+ class_infos[idx].hash = h;
+ }
+ }
+ }
+ else if (objc_opt->version >= 12 && objc_opt->version <= 15)
{
const objc_clsopt_t* clsopt = NULL;
if (objc_opt->version >= 14)
@@ -491,7 +657,8 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,
m_dynamic_class_info_extractor(*this),
m_shared_cache_class_info_extractor(*this), m_decl_vendor_up(),
m_tagged_pointer_obfuscator(LLDB_INVALID_ADDRESS),
- m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), m_hash_signature(),
+ m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS),
+ m_relative_selector_base(LLDB_INVALID_ADDRESS), m_hash_signature(),
m_has_object_getClass(false), m_has_objc_copyRealizedClassList(false),
m_loaded_objc_opt(false), m_non_pointer_isa_cache_up(),
m_tagged_pointer_vendor_up(
@@ -1515,6 +1682,9 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
CompilerType clang_void_pointer_type =
ast->GetBasicType(eBasicTypeVoid).GetPointerType();
+ CompilerType clang_uint64_t_pointer_type =
+ ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64)
+ .GetPointerType();
// Next make the function caller for our implementation utility function.
ValueList arguments;
@@ -1523,6 +1693,11 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
value.SetCompilerType(clang_void_pointer_type);
arguments.PushValue(value);
arguments.PushValue(value);
+ arguments.PushValue(value);
+
+ value.SetValueType(Value::ValueType::Scalar);
+ value.SetCompilerType(clang_uint64_t_pointer_type);
+ arguments.PushValue(value);
value.SetValueType(Value::ValueType::Scalar);
value.SetCompilerType(clang_uint32_t_type);
@@ -1816,8 +1991,11 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
uint32_t num_class_infos = 0;
const lldb::addr_t objc_opt_ptr = m_runtime.GetSharedCacheReadOnlyAddress();
+ const lldb::addr_t shared_cache_base_addr =
+ m_runtime.GetSharedCacheBaseAddress();
- if (objc_opt_ptr == LLDB_INVALID_ADDRESS)
+ if (objc_opt_ptr == LLDB_INVALID_ADDRESS ||
+ shared_cache_base_addr == LLDB_INVALID_ADDRESS)
return DescriptorMapUpdateResult::Fail();
const uint32_t num_classes = 128 * 1024;
@@ -1840,6 +2018,10 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
lldb::addr_t class_infos_addr = process->AllocateMemory(
class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
+ const uint32_t relative_selector_offset_addr_size = 64;
+ lldb::addr_t relative_selector_offset_addr =
+ process->AllocateMemory(relative_selector_offset_addr_size,
+ ePermissionsReadable | ePermissionsWritable, err);
if (class_infos_addr == LLDB_INVALID_ADDRESS) {
LLDB_LOGF(log,
@@ -1853,14 +2035,16 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
// Fill in our function argument values
arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
- arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
- arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
+ arguments.GetValueAtIndex(1)->GetScalar() = shared_cache_base_addr;
+ arguments.GetValueAtIndex(2)->GetScalar() = class_infos_addr;
+ arguments.GetValueAtIndex(3)->GetScalar() = relative_selector_offset_addr;
+ arguments.GetValueAtIndex(4)->GetScalar() = class_infos_byte_size;
// Only dump the runtime classes from the expression evaluation if the log is
// verbose:
Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES);
bool dump_log = type_log && type_log->GetVerbose();
- arguments.GetValueAtIndex(3)->GetScalar() = dump_log ? 1 : 0;
+ arguments.GetValueAtIndex(5)->GetScalar() = dump_log ? 1 : 0;
bool success = false;
@@ -1907,13 +2091,35 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
success = true;
}
+ // Read the relative selector offset.
+ DataBufferHeap relative_selector_offset_buffer(64, 0);
+ if (process->ReadMemory(relative_selector_offset_addr,
+ relative_selector_offset_buffer.GetBytes(),
+ relative_selector_offset_buffer.GetByteSize(),
+ err) ==
+ relative_selector_offset_buffer.GetByteSize()) {
+ DataExtractor relative_selector_offset_data(
+ relative_selector_offset_buffer.GetBytes(),
+ relative_selector_offset_buffer.GetByteSize(),
+ process->GetByteOrder(), addr_size);
+ lldb::offset_t offset = 0;
+ uint64_t relative_selector_offset =
+ relative_selector_offset_data.GetU64(&offset);
+ if (relative_selector_offset > 0) {
+ // The offset is relative to the objc_opt struct.
+ m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr +
+ relative_selector_offset);
+ }
+ }
+
// Read the ClassInfo structures
- DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0);
- if (process->ReadMemory(class_infos_addr, buffer.GetBytes(),
- buffer.GetByteSize(),
- err) == buffer.GetByteSize()) {
- DataExtractor class_infos_data(buffer.GetBytes(),
- buffer.GetByteSize(),
+ DataBufferHeap class_infos_buffer(
+ num_class_infos * class_info_byte_size, 0);
+ if (process->ReadMemory(class_infos_addr, class_infos_buffer.GetBytes(),
+ class_infos_buffer.GetByteSize(),
+ err) == class_infos_buffer.GetByteSize()) {
+ DataExtractor class_infos_data(class_infos_buffer.GetBytes(),
+ class_infos_buffer.GetByteSize(),
process->GetByteOrder(), addr_size);
m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);
@@ -1973,6 +2179,19 @@ lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() {
return LLDB_INVALID_ADDRESS;
}
+lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheBaseAddress() {
+ StructuredData::ObjectSP info = m_process->GetSharedCacheInfo();
+ if (!info)
+ return LLDB_INVALID_ADDRESS;
+
+ StructuredData::Dictionary *info_dict = info->GetAsDictionary();
+ if (!info_dict)
+ return LLDB_INVALID_ADDRESS;
+
+ return info_dict->GetValueForKey("shared_cache_base_address")
+ ->GetIntegerValue(LLDB_INVALID_ADDRESS);
+}
+
void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() {
LLDB_SCOPED_TIMER();
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
index 2da1670a3a0c0..d0caa2969115a 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -85,6 +85,15 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
lldb::addr_t GetTaggedPointerObfuscator();
+ /// Returns the base address for relative method list selector strings.
+ lldb::addr_t GetRelativeSelectorBaseAddr() {
+ return m_relative_selector_base;
+ }
+
+ void SetRelativeSelectorBaseAddr(lldb::addr_t relative_selector_base) {
+ m_relative_selector_base = relative_selector_base;
+ }
+
void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
lldb::addr_t &cf_false) override;
@@ -394,6 +403,7 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
void WarnIfNoClassesCached(SharedCacheWarningReason reason);
lldb::addr_t GetSharedCacheReadOnlyAddress();
+ lldb::addr_t GetSharedCacheBaseAddress();
bool GetCFBooleanValuesIfNeeded();
@@ -416,6 +426,7 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
std::unique_ptr<DeclVendor> m_decl_vendor_up;
lldb::addr_t m_tagged_pointer_obfuscator;
lldb::addr_t m_isa_hash_table_ptr;
+ lldb::addr_t m_relative_selector_base;
HashTableSignature m_hash_signature;
bool m_has_object_getClass;
bool m_has_objc_copyRealizedClassList;
More information about the lldb-commits
mailing list