forked from OSchip/llvm-project
[lldb/ObjCRuntime] Implement support for small method lists
On macOS 11 (and other aligned Apple OSs), the Objective-C runtime has a new optimization which saves memory by making the method lists smaller. This patch adds support for this new method list encoding (while also keeping backward compatibility). This is implicitely covered by some existing Objective-C tests.
This commit is contained in:
parent
e1a31f52cd
commit
61d22ef236
|
@ -241,15 +241,19 @@ bool ClassDescriptorV2::method_list_t::Read(Process *process,
|
|||
|
||||
lldb::offset_t cursor = 0;
|
||||
|
||||
m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3;
|
||||
uint32_t entsize = extractor.GetU32_unchecked(&cursor);
|
||||
m_is_small = (entsize & 0x80000000) != 0;
|
||||
m_entsize = entsize & 0xfffc;
|
||||
m_count = extractor.GetU32_unchecked(&cursor);
|
||||
m_first_ptr = addr + cursor;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) {
|
||||
size_t size = GetSize(process);
|
||||
bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr,
|
||||
bool is_small) {
|
||||
size_t ptr_size = process->GetAddressByteSize();
|
||||
size_t size = GetSize(process, is_small);
|
||||
|
||||
DataBufferHeap buffer(size, '\0');
|
||||
Status error;
|
||||
|
@ -260,13 +264,27 @@ bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) {
|
|||
}
|
||||
|
||||
DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
|
||||
process->GetAddressByteSize());
|
||||
|
||||
ptr_size);
|
||||
lldb::offset_t cursor = 0;
|
||||
|
||||
m_name_ptr = extractor.GetAddress_unchecked(&cursor);
|
||||
m_types_ptr = extractor.GetAddress_unchecked(&cursor);
|
||||
m_imp_ptr = extractor.GetAddress_unchecked(&cursor);
|
||||
if (is_small) {
|
||||
uint32_t nameref_offset = extractor.GetU32_unchecked(&cursor);
|
||||
uint32_t types_offset = extractor.GetU32_unchecked(&cursor);
|
||||
uint32_t imp_offset = extractor.GetU32_unchecked(&cursor);
|
||||
|
||||
// The SEL offset points to a SELRef. We need to dereference twice.
|
||||
lldb::addr_t selref_addr = addr + nameref_offset;
|
||||
m_name_ptr =
|
||||
process->ReadUnsignedIntegerFromMemory(selref_addr, ptr_size, 0, error);
|
||||
if (!error.Success())
|
||||
return false;
|
||||
m_types_ptr = addr + 4 + types_offset;
|
||||
m_imp_ptr = addr + 8 + imp_offset;
|
||||
} else {
|
||||
m_name_ptr = extractor.GetAddress_unchecked(&cursor);
|
||||
m_types_ptr = extractor.GetAddress_unchecked(&cursor);
|
||||
m_imp_ptr = extractor.GetAddress_unchecked(&cursor);
|
||||
}
|
||||
|
||||
process->ReadCStringFromMemory(m_name_ptr, m_name, error);
|
||||
if (error.Fail()) {
|
||||
|
@ -361,15 +379,18 @@ bool ClassDescriptorV2::Describe(
|
|||
if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr))
|
||||
return false;
|
||||
|
||||
if (base_method_list->m_entsize != method_t::GetSize(process))
|
||||
bool is_small = base_method_list->m_is_small;
|
||||
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>();
|
||||
|
||||
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));
|
||||
method->Read(process,
|
||||
base_method_list->m_first_ptr +
|
||||
(i * base_method_list->m_entsize),
|
||||
is_small);
|
||||
|
||||
if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
|
||||
break;
|
||||
|
|
|
@ -133,7 +133,8 @@ private:
|
|||
};
|
||||
|
||||
struct method_list_t {
|
||||
uint32_t m_entsize;
|
||||
uint16_t m_entsize;
|
||||
bool m_is_small;
|
||||
uint32_t m_count;
|
||||
lldb::addr_t m_first_ptr;
|
||||
|
||||
|
@ -148,15 +149,19 @@ private:
|
|||
std::string m_name;
|
||||
std::string m_types;
|
||||
|
||||
static size_t GetSize(Process *process) {
|
||||
size_t ptr_size = process->GetAddressByteSize();
|
||||
static size_t GetSize(Process *process, bool is_small) {
|
||||
size_t field_size;
|
||||
if (is_small)
|
||||
field_size = 4; // uint32_t relative indirect fields
|
||||
else
|
||||
field_size = process->GetAddressByteSize();
|
||||
|
||||
return ptr_size // SEL name;
|
||||
+ ptr_size // const char *types;
|
||||
+ ptr_size; // IMP imp;
|
||||
return field_size // SEL name;
|
||||
+ field_size // const char *types;
|
||||
+ field_size; // IMP imp;
|
||||
}
|
||||
|
||||
bool Read(Process *process, lldb::addr_t addr);
|
||||
bool Read(Process *process, lldb::addr_t addr, bool);
|
||||
};
|
||||
|
||||
struct ivar_list_t {
|
||||
|
|
Loading…
Reference in New Issue