static plcrash_error_t pl_async_objc_parse_objc2_category_methods()

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;
}