Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5b9984c

Browse files
authored
Merge pull request swiftlang#7025 from bulbazord/5.9-objc-runtime-change
[lldb] Adjust for changes in objc runtime
2 parents a062717 + 4b5399b commit 5b9984c

File tree

5 files changed

+400
-26
lines changed

5 files changed

+400
-26
lines changed

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp

+161-23
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,155 @@ bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) {
370370
return !error.Fail();
371371
}
372372

373+
bool ClassDescriptorV2::relative_list_entry_t::Read(Process *process,
374+
lldb::addr_t addr) {
375+
Log *log = GetLog(LLDBLog::Types);
376+
size_t size = sizeof(uint64_t); // m_image_index : 16
377+
// m_list_offset : 48
378+
379+
DataBufferHeap buffer(size, '\0');
380+
Status error;
381+
382+
process->ReadMemory(addr, buffer.GetBytes(), size, error);
383+
// FIXME: Propagate this error up
384+
if (error.Fail()) {
385+
LLDB_LOG(log, "Failed to read relative_list_entry_t at address {0:x}",
386+
addr);
387+
return false;
388+
}
389+
390+
DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
391+
process->GetAddressByteSize());
392+
lldb::offset_t cursor = 0;
393+
uint64_t raw_entry = extractor.GetU64_unchecked(&cursor);
394+
m_image_index = raw_entry & 0xFFFF;
395+
m_list_offset = (int64_t)(raw_entry >> 16);
396+
return true;
397+
}
398+
399+
bool ClassDescriptorV2::relative_list_list_t::Read(Process *process,
400+
lldb::addr_t addr) {
401+
Log *log = GetLog(LLDBLog::Types);
402+
size_t size = sizeof(uint32_t) // m_entsize
403+
+ sizeof(uint32_t); // m_count
404+
405+
DataBufferHeap buffer(size, '\0');
406+
Status error;
407+
408+
// FIXME: Propagate this error up
409+
process->ReadMemory(addr, buffer.GetBytes(), size, error);
410+
if (error.Fail()) {
411+
LLDB_LOG(log, "Failed to read relative_list_list_t at address 0x" PRIx64,
412+
addr);
413+
return false;
414+
}
415+
416+
DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
417+
process->GetAddressByteSize());
418+
lldb::offset_t cursor = 0;
419+
m_entsize = extractor.GetU32_unchecked(&cursor);
420+
m_count = extractor.GetU32_unchecked(&cursor);
421+
m_first_ptr = addr + cursor;
422+
return true;
423+
}
424+
425+
std::optional<ClassDescriptorV2::method_list_t>
426+
ClassDescriptorV2::GetMethodList(Process *process,
427+
lldb::addr_t method_list_ptr) const {
428+
Log *log = GetLog(LLDBLog::Types);
429+
ClassDescriptorV2::method_list_t method_list;
430+
if (!method_list.Read(process, method_list_ptr))
431+
return std::nullopt;
432+
433+
const size_t method_size = method_t::GetSize(process, method_list.m_is_small);
434+
if (method_list.m_entsize != method_size) {
435+
LLDB_LOG(log,
436+
"method_list_t at address 0x" PRIx64 " has an entsize of " PRIu16
437+
" but method size should be " PRIu64,
438+
method_list_ptr, method_list.m_entsize, method_size);
439+
return std::nullopt;
440+
}
441+
442+
return method_list;
443+
}
444+
445+
bool ClassDescriptorV2::ProcessMethodList(
446+
std::function<bool(const char *, const char *)> const &instance_method_func,
447+
ClassDescriptorV2::method_list_t &method_list) const {
448+
lldb_private::Process *process = m_runtime.GetProcess();
449+
auto method = std::make_unique<method_t>();
450+
lldb::addr_t relative_selector_base_addr =
451+
m_runtime.GetRelativeSelectorBaseAddr();
452+
for (uint32_t i = 0, e = method_list.m_count; i < e; ++i) {
453+
method->Read(process, method_list.m_first_ptr + (i * method_list.m_entsize),
454+
relative_selector_base_addr, method_list.m_is_small,
455+
method_list.m_has_direct_selector);
456+
if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
457+
break;
458+
}
459+
return true;
460+
}
461+
462+
// The relevant data structures:
463+
// - relative_list_list_t
464+
// - uint32_t count
465+
// - uint32_t entsize
466+
// - Followed by <count> number of relative_list_entry_t of size <entsize>
467+
//
468+
// - relative_list_entry_t
469+
// - uint64_t image_index : 16
470+
// - int64_t list_offset : 48
471+
// - Note: The above 2 fit into 8 bytes always
472+
//
473+
// image_index corresponds to an image in the shared cache
474+
// list_offset is used to calculate the address of the method_list_t we want
475+
bool ClassDescriptorV2::ProcessRelativeMethodLists(
476+
std::function<bool(const char *, const char *)> const &instance_method_func,
477+
lldb::addr_t relative_method_list_ptr) const {
478+
lldb_private::Process *process = m_runtime.GetProcess();
479+
auto relative_method_lists = std::make_unique<relative_list_list_t>();
480+
481+
// 1. Process the count and entsize of the relative_list_list_t
482+
if (!relative_method_lists->Read(process, relative_method_list_ptr))
483+
return false;
484+
485+
auto entry = std::make_unique<relative_list_entry_t>();
486+
for (uint32_t i = 0; i < relative_method_lists->m_count; i++) {
487+
// 2. Extract the image index and the list offset from the
488+
// relative_list_entry_t
489+
const lldb::addr_t entry_addr = relative_method_lists->m_first_ptr +
490+
(i * relative_method_lists->m_entsize);
491+
if (!entry->Read(process, entry_addr))
492+
return false;
493+
494+
// 3. Calculate the pointer to the method_list_t from the
495+
// relative_list_entry_t
496+
const lldb::addr_t method_list_addr = entry_addr + entry->m_list_offset;
497+
498+
// 4. Get the method_list_t from the pointer
499+
std::optional<method_list_t> method_list =
500+
GetMethodList(process, method_list_addr);
501+
if (!method_list)
502+
return false;
503+
504+
// 5. Cache the result so we don't need to reconstruct it later.
505+
m_image_to_method_lists[entry->m_image_index].emplace_back(*method_list);
506+
507+
// 6. If the relevant image is loaded, add the methods to the Decl
508+
if (!m_runtime.IsSharedCacheImageLoaded(entry->m_image_index))
509+
continue;
510+
511+
if (!ProcessMethodList(instance_method_func, *method_list))
512+
return false;
513+
}
514+
515+
// We need to keep track of the last time we updated so we can re-update the
516+
// type information in the future
517+
m_last_version_updated = m_runtime.GetSharedCacheImageHeaderVersion();
518+
519+
return true;
520+
}
521+
373522
bool ClassDescriptorV2::Describe(
374523
std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
375524
std::function<bool(const char *, const char *)> const &instance_method_func,
@@ -393,29 +542,18 @@ bool ClassDescriptorV2::Describe(
393542
superclass_func(objc_class->m_superclass);
394543

395544
if (instance_method_func) {
396-
std::unique_ptr<method_list_t> base_method_list;
397-
398-
base_method_list = std::make_unique<method_list_t>();
399-
if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr))
400-
return false;
401-
402-
bool is_small = base_method_list->m_is_small;
403-
bool has_direct_selector = base_method_list->m_has_direct_selector;
404-
405-
if (base_method_list->m_entsize != method_t::GetSize(process, is_small))
406-
return false;
407-
408-
std::unique_ptr<method_t> method = std::make_unique<method_t>();
409-
lldb::addr_t relative_selector_base_addr =
410-
m_runtime.GetRelativeSelectorBaseAddr();
411-
for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) {
412-
method->Read(process,
413-
base_method_list->m_first_ptr +
414-
(i * base_method_list->m_entsize),
415-
relative_selector_base_addr, is_small, has_direct_selector);
416-
417-
if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
418-
break;
545+
// This is a relative list of lists
546+
if (class_ro->m_baseMethods_ptr & 1) {
547+
if (!ProcessRelativeMethodLists(instance_method_func,
548+
class_ro->m_baseMethods_ptr ^ 1))
549+
return false;
550+
} else {
551+
std::optional<method_list_t> base_method_list =
552+
GetMethodList(process, class_ro->m_baseMethods_ptr);
553+
if (!base_method_list)
554+
return false;
555+
if (!ProcessMethodList(instance_method_func, *base_method_list))
556+
return false;
419557
}
420558
}
421559

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h

+33-1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
146146
bool Read(Process *process, lldb::addr_t addr);
147147
};
148148

149+
std::optional<method_list_t>
150+
GetMethodList(Process *process, lldb::addr_t method_list_ptr) const;
151+
149152
struct method_t {
150153
lldb::addr_t m_name_ptr;
151154
lldb::addr_t m_types_ptr;
@@ -201,6 +204,21 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
201204
bool Read(Process *process, lldb::addr_t addr);
202205
};
203206

207+
struct relative_list_entry_t {
208+
uint16_t m_image_index;
209+
int64_t m_list_offset;
210+
211+
bool Read(Process *process, lldb::addr_t addr);
212+
};
213+
214+
struct relative_list_list_t {
215+
uint32_t m_entsize;
216+
uint32_t m_count;
217+
lldb::addr_t m_first_ptr;
218+
219+
bool Read(Process *process, lldb::addr_t addr);
220+
};
221+
204222
class iVarsStorage {
205223
public:
206224
iVarsStorage();
@@ -223,7 +241,8 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
223241
ClassDescriptorV2(AppleObjCRuntimeV2 &runtime,
224242
ObjCLanguageRuntime::ObjCISA isa, const char *name)
225243
: m_runtime(runtime), m_objc_class_ptr(isa), m_name(name),
226-
m_ivars_storage() {}
244+
m_ivars_storage(), m_image_to_method_lists(), m_last_version_updated() {
245+
}
227246

228247
bool Read_objc_class(Process *process,
229248
std::unique_ptr<objc_class_t> &objc_class) const;
@@ -232,13 +251,26 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
232251
std::unique_ptr<class_ro_t> &class_ro,
233252
std::unique_ptr<class_rw_t> &class_rw) const;
234253

254+
bool ProcessMethodList(std::function<bool(const char *, const char *)> const
255+
&instance_method_func,
256+
method_list_t &method_list) const;
257+
258+
bool ProcessRelativeMethodLists(
259+
std::function<bool(const char *, const char *)> const
260+
&instance_method_func,
261+
lldb::addr_t relative_method_list_ptr) const;
262+
235263
AppleObjCRuntimeV2
236264
&m_runtime; // The runtime, so we can read information lazily.
237265
lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e.,
238266
// objects of this class type have this as
239267
// their ISA)
240268
ConstString m_name; // May be NULL
241269
iVarsStorage m_ivars_storage;
270+
271+
mutable std::map<uint16_t, std::vector<method_list_t>>
272+
m_image_to_method_lists;
273+
mutable std::optional<uint64_t> m_last_version_updated;
242274
};
243275

244276
// tagged pointer descriptor

0 commit comments

Comments
 (0)