in Source/PLCrashAsyncObjCSection.mm [973:1015]
static plcrash_error_t pl_async_objc_parse_objc2_category_methods (plcrash_async_macho_t *image, plcrash_async_objc_cache_t *objc_cache, category_t *category, plcrash_async_objc_found_method_cb callback, void *ctx) {
plcrash_async_macho_string_t class_name;
class_ro_t cls_data_ro;
plcrash_error_t err;
/* Grab the class reference and parse the class. We try to simply remap the pointer, but if that fails, we perform a more
* expensive read. */
pl_vm_address_t ptr = (pl_vm_address_t) image->byteorder->swap(category->cls);
class_t *classPtr = (class_t *) plcrash_async_mobject_remap_address(&objc_cache->objcDataMobj, ptr, 0, sizeof(*classPtr));
class_t class_data;
if (classPtr == NULL) {
if ((err = plcrash_async_task_memcpy(image->task, ptr, 0, &class_data, sizeof(class_data))) != PLCRASH_ESUCCESS) {
PLCF_DEBUG("plcrash_async_task_memcpy() for pointer 0x%llx returned NULL", (long long)ptr);
return PLCRASH_EINVALID_DATA;
}
classPtr = &class_data;
}
if ((err = pl_async_objc_parse_objc2_class<class_t, class_ro_t, class_rw_t, machine_ptr_t>(image, objc_cache, classPtr, &class_name, &cls_data_ro)) != PLCRASH_ESUCCESS)
return err;
/* Fetch and parse the instance and class method lists. The method list will be NULL if no methods are defined for the category; in that case, we simply skip the category. */
pl_vm_address_t methods_ptr = (pl_vm_address_t) image->byteorder->swap(category->instanceMethods);
if (methods_ptr != 0) {
if ((err = pl_async_objc_parse_objc2_method_list(image, objc_cache, &class_name, false, methods_ptr, callback, ctx)) != PLCRASH_ESUCCESS)
goto cleanup;
}
methods_ptr = (pl_vm_address_t) image->byteorder->swap(category->classMethods);
if (methods_ptr != 0) {
if ((err = pl_async_objc_parse_objc2_method_list(image, objc_cache, &class_name, true, methods_ptr, callback, ctx)) != PLCRASH_ESUCCESS)
goto cleanup;
}
err = PLCRASH_ESUCCESS;
cleanup:
/* Clean up */
plcrash_async_macho_string_free(&class_name);
return err;
}