in Source/PLCrashAsyncObjCSection.mm [729:803]
static plcrash_error_t pl_async_objc_parse_objc2_method_list (plcrash_async_macho_t *image,
plcrash_async_objc_cache_t *objc_cache,
plcrash_async_macho_string_t *class_name,
bool is_meta_class,
pl_vm_address_t method_list_addr,
plcrash_async_objc_found_method_cb callback,
void *ctx)
{
PLCF_ASSERT(method_list_addr != 0);
/* Read the method list header. */
struct pl_objc2_list_header *header;
plcrash_async_mobject_t *section = &objc_cache->objcConstMobj;
header = (struct pl_objc2_list_header *) plcrash_async_mobject_remap_address(section, method_list_addr, 0, sizeof(*header));
if (header == NULL && objc_cache->objcConstAxMobjInitialized) {
section = &objc_cache->objcConstAxMobj;
header = (struct pl_objc2_list_header *) plcrash_async_mobject_remap_address(section, method_list_addr, 0, sizeof(*header));
}
if (header == NULL) {
PLCF_DEBUG("plcrash_async_mobject_remap_address in __objc_const and __objc_const_ax failed to map methods pointer 0x%llx", (long long) method_list_addr);
return PLCRASH_EINVALID_DATA;
}
/* Extract the entry size and count from the list header. */
uint32_t entsize = image->byteorder->swap32(header->entsize) & ~(uint32_t)3;
uint32_t count = image->byteorder->swap32(header->count);
/* Compute the method list start position and length. */
pl_vm_address_t method_list_start = method_list_addr + sizeof(*header);
pl_vm_size_t method_list_length = (pl_vm_size_t)entsize * count;
const char *cursor = (const char *) plcrash_async_mobject_remap_address(section, method_list_start, 0, method_list_length);
if (cursor == NULL) {
PLCF_DEBUG("plcrash_async_mobject_remap_address at 0x%llx length %llu returned NULL", (long long)method_list_start, (unsigned long long)method_list_length);
return PLCRASH_EINVALID_DATA;
}
/* Extract methods from the list. */
for (uint32_t i = 0; i < count; i++) {
plcrash_error_t err;
/* Read an architecture-appropriate method structure from the
* current cursor. */
const struct pl_objc2_method_32 *method_32 = (const struct pl_objc2_method_32 *)cursor;
const struct pl_objc2_method_64 *method_64 = (const struct pl_objc2_method_64 *)cursor;
/* Extract the method name pointer. */
pl_vm_address_t methodNamePtr = (image->m64
? (pl_vm_address_t) image->byteorder->swap64(method_64->name)
: image->byteorder->swap32(method_32->name));
/* Read the method name. */
plcrash_async_macho_string_t method_name;
if ((err = plcrash_async_macho_string_init(&method_name, image, methodNamePtr)) != PLCRASH_ESUCCESS) {
PLCF_DEBUG("plcrash_async_macho_string_init at 0x%llx error %d", (long long)methodNamePtr, err);
return err;
}
/* Extract the method IMP. */
pl_vm_address_t imp = (image->m64
? (pl_vm_address_t) image->byteorder->swap64(method_64->imp)
: image->byteorder->swap32(method_32->imp));
/* Call the callback. */
callback(is_meta_class, class_name, &method_name, imp, ctx);
/* Clean up the method name. */
plcrash_async_macho_string_free(&method_name);
/* Increment the cursor by the entry size for the next iteration of the loop. */
cursor += entsize;
}
return PLCRASH_ESUCCESS;
}