diff options
author | Jörg Wagner <jorwag@google.com> | 2023-12-14 09:44:26 +0000 |
---|---|---|
committer | Jörg Wagner <jorwag@google.com> | 2023-12-14 09:44:26 +0000 |
commit | 049a542207ed694271316782397b78b2e202086a (patch) | |
tree | 105e9378d4d5062dc72109fdd4a77c915bd9425d /mali_kbase/tests/kutf | |
parent | e61eb93296e9f940b32d4ad4b0c3a5557cbeaf17 (diff) | |
download | gpu-049a542207ed694271316782397b78b2e202086a.tar.gz |
Update KMD to r47p0
Provenance: ipdelivery@ad01e50d640910a99224382bb227e6d4de627657
Change-Id: I19ac9bce34a5c5a319c1b4a388e8b037b3dfe6e7
Diffstat (limited to 'mali_kbase/tests/kutf')
-rw-r--r-- | mali_kbase/tests/kutf/Kbuild | 5 | ||||
-rw-r--r-- | mali_kbase/tests/kutf/build.bp | 3 | ||||
-rw-r--r-- | mali_kbase/tests/kutf/kutf_helpers.c | 13 | ||||
-rw-r--r-- | mali_kbase/tests/kutf/kutf_helpers_user.c | 160 | ||||
-rw-r--r-- | mali_kbase/tests/kutf/kutf_kprobe.c | 344 | ||||
-rw-r--r-- | mali_kbase/tests/kutf/kutf_mem.c | 4 | ||||
-rw-r--r-- | mali_kbase/tests/kutf/kutf_resultset.c | 18 | ||||
-rw-r--r-- | mali_kbase/tests/kutf/kutf_suite.c | 334 | ||||
-rw-r--r-- | mali_kbase/tests/kutf/kutf_utils.c | 11 |
9 files changed, 600 insertions, 292 deletions
diff --git a/mali_kbase/tests/kutf/Kbuild b/mali_kbase/tests/kutf/Kbuild index c4790bc..aef44e0 100644 --- a/mali_kbase/tests/kutf/Kbuild +++ b/mali_kbase/tests/kutf/Kbuild @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note # -# (C) COPYRIGHT 2017, 2020-2021 ARM Limited. All rights reserved. +# (C) COPYRIGHT 2017, 2020-2023 ARM Limited. All rights reserved. # # This program is free software and is provided to you under the terms of the # GNU General Public License version 2 as published by the Free Software @@ -27,5 +27,6 @@ kutf-y := \ kutf_suite.o \ kutf_utils.o \ kutf_helpers.o \ - kutf_helpers_user.o + kutf_helpers_user.o \ + kutf_kprobe.o endif diff --git a/mali_kbase/tests/kutf/build.bp b/mali_kbase/tests/kutf/build.bp index 89edae9..267c14b 100644 --- a/mali_kbase/tests/kutf/build.bp +++ b/mali_kbase/tests/kutf/build.bp @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * - * (C) COPYRIGHT 2018-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2018-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -34,6 +34,7 @@ bob_kernel_module { "kutf_resultset.c", "kutf_suite.c", "kutf_utils.c", + "kutf_kprobe.c", ], enabled: false, mali_kutf: { diff --git a/mali_kbase/tests/kutf/kutf_helpers.c b/mali_kbase/tests/kutf/kutf_helpers.c index 4273619..e0fe598 100644 --- a/mali_kbase/tests/kutf/kutf_helpers.c +++ b/mali_kbase/tests/kutf/kutf_helpers.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2017, 2020-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2017-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -59,7 +59,7 @@ char *kutf_helper_input_dequeue(struct kutf_context *context, size_t *str_size) spin_unlock(&kutf_input_lock); err = wait_event_interruptible(context->userdata.input_waitq, - kutf_helper_pending_input(context)); + kutf_helper_pending_input(context)); if (err) return ERR_PTR(-EINTR); @@ -67,8 +67,7 @@ char *kutf_helper_input_dequeue(struct kutf_context *context, size_t *str_size) spin_lock(&kutf_input_lock); } - line = list_first_entry(&context->userdata.input_head, - struct kutf_userdata_line, node); + line = list_first_entry(&context->userdata.input_head, struct kutf_userdata_line, node); if (line->str) { /* * Unless it is the end-of-input marker, @@ -84,13 +83,11 @@ char *kutf_helper_input_dequeue(struct kutf_context *context, size_t *str_size) return line->str; } -int kutf_helper_input_enqueue(struct kutf_context *context, - const char __user *str, size_t size) +int kutf_helper_input_enqueue(struct kutf_context *context, const char __user *str, size_t size) { struct kutf_userdata_line *line; - line = kutf_mempool_alloc(&context->fixture_pool, - sizeof(*line) + size + 1); + line = kutf_mempool_alloc(&context->fixture_pool, sizeof(*line) + size + 1); if (!line) return -ENOMEM; if (str) { diff --git a/mali_kbase/tests/kutf/kutf_helpers_user.c b/mali_kbase/tests/kutf/kutf_helpers_user.c index c4e2943..a69c791 100644 --- a/mali_kbase/tests/kutf/kutf_helpers_user.c +++ b/mali_kbase/tests/kutf/kutf_helpers_user.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2017, 2020-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2017-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -56,11 +56,12 @@ static const char *get_val_type_name(enum kutf_helper_valtype valtype) * - Has between 1 and KUTF_HELPER_MAX_VAL_NAME_LEN characters before the \0 terminator * - And, each char is in the character set [A-Z0-9_] */ -static int validate_val_name(const char *val_str, int str_len) +static int validate_val_name(const char *val_str, size_t str_len) { int i = 0; - for (i = 0; str_len && i <= KUTF_HELPER_MAX_VAL_NAME_LEN && val_str[i] != '\0'; ++i, --str_len) { + for (i = 0; str_len && i <= KUTF_HELPER_MAX_VAL_NAME_LEN && val_str[i] != '\0'; + ++i, --str_len) { char val_chr = val_str[i]; if (val_chr >= 'A' && val_chr <= 'Z') @@ -78,7 +79,8 @@ static int validate_val_name(const char *val_str, int str_len) if (i == 0) return 1; /* Length greater than KUTF_HELPER_MAX_VAL_NAME_LEN not allowed */ - if (i > KUTF_HELPER_MAX_VAL_NAME_LEN || (i == KUTF_HELPER_MAX_VAL_NAME_LEN && val_str[i] != '\0')) + if (i > KUTF_HELPER_MAX_VAL_NAME_LEN || + (i == KUTF_HELPER_MAX_VAL_NAME_LEN && val_str[i] != '\0')) return 1; return 0; @@ -90,32 +92,31 @@ static int validate_val_name(const char *val_str, int str_len) * That is, before any '\\', '\n' or '"' characters. This is so we don't have * to escape the string */ -static int find_quoted_string_valid_len(const char *str) +static size_t find_quoted_string_valid_len(const char *str) { char *ptr; const char *check_chars = "\\\n\""; ptr = strpbrk(str, check_chars); if (ptr) - return (int)(ptr-str); + return (size_t)(ptr - str); - return (int)strlen(str); + return strlen(str); } -static int kutf_helper_userdata_enqueue(struct kutf_context *context, - const char *str) +static int kutf_helper_userdata_enqueue(struct kutf_context *context, const char *str) { char *str_copy; size_t len; int err; - len = strlen(str)+1; + len = strlen(str) + 1; str_copy = kutf_mempool_alloc(&context->fixture_pool, len); if (!str_copy) return -ENOMEM; - strcpy(str_copy, str); + strscpy(str_copy, str, len); err = kutf_add_result(context, KUTF_RESULT_USERDATA, str_copy); @@ -126,8 +127,7 @@ static int kutf_helper_userdata_enqueue(struct kutf_context *context, /* (Name size) + ("=0x" size) + (64-bit hex value size) + (terminator) */ #define NAMED_U64_VAL_BUF_SZ (KUTF_HELPER_MAX_VAL_NAME_LEN + 3 + MAX_U64_HEX_LEN + 1) -int kutf_helper_send_named_u64(struct kutf_context *context, - const char *val_name, u64 val) +int kutf_helper_send_named_u64(struct kutf_context *context, const char *val_name, u64 val) { int ret = 1; char msgbuf[NAMED_U64_VAL_BUF_SZ]; @@ -135,23 +135,25 @@ int kutf_helper_send_named_u64(struct kutf_context *context, if (validate_val_name(val_name, KUTF_HELPER_MAX_VAL_NAME_LEN + 1)) { errmsg = kutf_dsprintf(&context->fixture_pool, - "Failed to send u64 value named '%s': Invalid value name", val_name); + "Failed to send u64 value named '%s': Invalid value name", + val_name); goto out_err; } ret = snprintf(msgbuf, NAMED_U64_VAL_BUF_SZ, "%s=0x%llx", val_name, val); if (ret >= NAMED_U64_VAL_BUF_SZ || ret < 0) { - errmsg = kutf_dsprintf(&context->fixture_pool, - "Failed to send u64 value named '%s': snprintf() problem buffer size==%d ret=%d", - val_name, NAMED_U64_VAL_BUF_SZ, ret); + errmsg = kutf_dsprintf( + &context->fixture_pool, + "Failed to send u64 value named '%s': snprintf() problem buffer size==%d ret=%d", + val_name, NAMED_U64_VAL_BUF_SZ, ret); goto out_err; } ret = kutf_helper_userdata_enqueue(context, msgbuf); if (ret) { errmsg = kutf_dsprintf(&context->fixture_pool, - "Failed to send u64 value named '%s': send returned %d", - val_name, ret); + "Failed to send u64 value named '%s': send returned %d", + val_name, ret); goto out_err; } @@ -166,8 +168,7 @@ EXPORT_SYMBOL(kutf_helper_send_named_u64); #define NAMED_STR_START_DELIM NAMED_VALUE_SEP "\"" #define NAMED_STR_END_DELIM "\"" -int kutf_helper_max_str_len_for_kern(const char *val_name, - int kern_buf_sz) +int kutf_helper_max_str_len_for_kern(const char *val_name, int kern_buf_sz) { const int val_name_len = strlen(val_name); const int start_delim_len = strlen(NAMED_STR_START_DELIM); @@ -175,30 +176,29 @@ int kutf_helper_max_str_len_for_kern(const char *val_name, int max_msg_len = kern_buf_sz; int max_str_len; - max_str_len = max_msg_len - val_name_len - start_delim_len - - end_delim_len; + max_str_len = max_msg_len - val_name_len - start_delim_len - end_delim_len; return max_str_len; } EXPORT_SYMBOL(kutf_helper_max_str_len_for_kern); -int kutf_helper_send_named_str(struct kutf_context *context, - const char *val_name, - const char *val_str) +int kutf_helper_send_named_str(struct kutf_context *context, const char *val_name, + const char *val_str) { - int val_str_len; - int str_buf_sz; + size_t val_str_len; + size_t str_buf_sz; char *str_buf = NULL; int ret = 1; char *copy_ptr; - int val_name_len; - int start_delim_len = strlen(NAMED_STR_START_DELIM); - int end_delim_len = strlen(NAMED_STR_END_DELIM); + size_t val_name_len; + size_t start_delim_len = strlen(NAMED_STR_START_DELIM); + size_t end_delim_len = strlen(NAMED_STR_END_DELIM); const char *errmsg = NULL; if (validate_val_name(val_name, KUTF_HELPER_MAX_VAL_NAME_LEN + 1)) { errmsg = kutf_dsprintf(&context->fixture_pool, - "Failed to send u64 value named '%s': Invalid value name", val_name); + "Failed to send u64 value named '%s': Invalid value name", + val_name); goto out_err; } val_name_len = strlen(val_name); @@ -213,9 +213,10 @@ int kutf_helper_send_named_str(struct kutf_context *context, */ str_buf = kmalloc(str_buf_sz, GFP_KERNEL); if (!str_buf) { - errmsg = kutf_dsprintf(&context->fixture_pool, - "Failed to send str value named '%s': kmalloc failed, str_buf_sz=%d", - val_name, str_buf_sz); + errmsg = kutf_dsprintf( + &context->fixture_pool, + "Failed to send str value named '%s': kmalloc failed, str_buf_sz=%zu", + val_name, str_buf_sz); goto out_err; } copy_ptr = str_buf; @@ -247,8 +248,8 @@ int kutf_helper_send_named_str(struct kutf_context *context, if (ret) { errmsg = kutf_dsprintf(&context->fixture_pool, - "Failed to send str value named '%s': send returned %d", - val_name, ret); + "Failed to send str value named '%s': send returned %d", + val_name, ret); goto out_err; } @@ -262,16 +263,15 @@ out_err: } EXPORT_SYMBOL(kutf_helper_send_named_str); -int kutf_helper_receive_named_val( - struct kutf_context *context, - struct kutf_helper_named_val *named_val) +int kutf_helper_receive_named_val(struct kutf_context *context, + struct kutf_helper_named_val *named_val) { size_t recv_sz; char *recv_str; char *search_ptr; char *name_str = NULL; - int name_len; - int strval_len; + size_t name_len; + size_t strval_len; enum kutf_helper_valtype type = KUTF_HELPER_VALTYPE_INVALID; char *strval = NULL; u64 u64val = 0; @@ -286,7 +286,7 @@ int kutf_helper_receive_named_val( /* Find the '=', grab the name and validate it */ search_ptr = strnchr(recv_str, recv_sz, NAMED_VALUE_SEP[0]); if (search_ptr) { - name_len = search_ptr - recv_str; + name_len = (size_t)(search_ptr - recv_str); if (!validate_val_name(recv_str, name_len)) { /* no need to reallocate - just modify string in place */ name_str = recv_str; @@ -298,8 +298,7 @@ int kutf_helper_receive_named_val( } } if (!name_str) { - pr_err("Invalid name part for received string '%s'\n", - recv_str); + pr_err("Invalid name part for received string '%s'\n", recv_str); return KUTF_HELPER_ERR_INVALID_NAME; } @@ -312,7 +311,7 @@ int kutf_helper_receive_named_val( /* Find end of string */ search_ptr = strnchr(recv_str, recv_sz, NAMED_STR_END_DELIM[0]); if (search_ptr) { - strval_len = search_ptr - recv_str; + strval_len = (size_t)(search_ptr - recv_str); /* Validate the string to ensure it contains no quotes */ if (strval_len == find_quoted_string_valid_len(recv_str)) { /* no need to reallocate - just modify string in place */ @@ -324,11 +323,13 @@ int kutf_helper_receive_named_val( recv_sz -= (strval_len + 1); type = KUTF_HELPER_VALTYPE_STR; } else { - pr_err("String value contains invalid characters in rest of received string '%s'\n", recv_str); + pr_err("String value contains invalid characters in rest of received string '%s'\n", + recv_str); err = KUTF_HELPER_ERR_CHARS_AFTER_VAL; } } else { - pr_err("End of string delimiter not found in rest of received string '%s'\n", recv_str); + pr_err("End of string delimiter not found in rest of received string '%s'\n", + recv_str); err = KUTF_HELPER_ERR_NO_END_DELIMITER; } } else { @@ -338,14 +339,15 @@ int kutf_helper_receive_named_val( * reads characters after the number it'll report -EINVAL */ if (!err) { - int len_remain = strnlen(recv_str, recv_sz); + size_t len_remain = strnlen(recv_str, recv_sz); type = KUTF_HELPER_VALTYPE_U64; recv_str += len_remain; recv_sz -= len_remain; } else { /* special case: not a number, report as such */ - pr_err("Rest of received string was not a numeric value or quoted string value: '%s'\n", recv_str); + pr_err("Rest of received string was not a numeric value or quoted string value: '%s'\n", + recv_str); } } @@ -354,8 +356,8 @@ int kutf_helper_receive_named_val( /* Any remaining characters - error */ if (strnlen(recv_str, recv_sz) != 0) { - pr_err("Characters remain after value of type %s: '%s'\n", - get_val_type_name(type), recv_str); + pr_err("Characters remain after value of type %s: '%s'\n", get_val_type_name(type), + recv_str); return KUTF_HELPER_ERR_CHARS_AFTER_VAL; } @@ -381,44 +383,41 @@ int kutf_helper_receive_named_val( EXPORT_SYMBOL(kutf_helper_receive_named_val); #define DUMMY_MSG "<placeholder due to test fail>" -int kutf_helper_receive_check_val( - struct kutf_helper_named_val *named_val, - struct kutf_context *context, - const char *expect_val_name, - enum kutf_helper_valtype expect_val_type) +int kutf_helper_receive_check_val(struct kutf_helper_named_val *named_val, + struct kutf_context *context, const char *expect_val_name, + enum kutf_helper_valtype expect_val_type) { int err; err = kutf_helper_receive_named_val(context, named_val); if (err < 0) { const char *msg = kutf_dsprintf(&context->fixture_pool, - "Failed to receive value named '%s'", - expect_val_name); + "Failed to receive value named '%s'", + expect_val_name); kutf_test_fail(context, msg); return err; } else if (err > 0) { - const char *msg = kutf_dsprintf(&context->fixture_pool, - "Named-value parse error when expecting value named '%s'", - expect_val_name); + const char *msg = kutf_dsprintf( + &context->fixture_pool, + "Named-value parse error when expecting value named '%s'", expect_val_name); kutf_test_fail(context, msg); goto out_fail_and_fixup; } - if (named_val->val_name != NULL && - strcmp(named_val->val_name, expect_val_name) != 0) { - const char *msg = kutf_dsprintf(&context->fixture_pool, - "Expecting to receive value named '%s' but got '%s'", - expect_val_name, named_val->val_name); + if (named_val->val_name != NULL && strcmp(named_val->val_name, expect_val_name) != 0) { + const char *msg = + kutf_dsprintf(&context->fixture_pool, + "Expecting to receive value named '%s' but got '%s'", + expect_val_name, named_val->val_name); kutf_test_fail(context, msg); goto out_fail_and_fixup; } - if (named_val->type != expect_val_type) { - const char *msg = kutf_dsprintf(&context->fixture_pool, - "Expecting value named '%s' to be of type %s but got %s", - expect_val_name, get_val_type_name(expect_val_type), - get_val_type_name(named_val->type)); + const char *msg = kutf_dsprintf( + &context->fixture_pool, + "Expecting value named '%s' to be of type %s but got %s", expect_val_name, + get_val_type_name(expect_val_type), get_val_type_name(named_val->type)); kutf_test_fail(context, msg); goto out_fail_and_fixup; } @@ -431,17 +430,16 @@ out_fail_and_fixup: case KUTF_HELPER_VALTYPE_U64: named_val->u.val_u64 = 0ull; break; - case KUTF_HELPER_VALTYPE_STR: - { - char *str = kutf_mempool_alloc(&context->fixture_pool, sizeof(DUMMY_MSG)); + case KUTF_HELPER_VALTYPE_STR: { + char *str = kutf_mempool_alloc(&context->fixture_pool, sizeof(DUMMY_MSG)); - if (!str) - return -1; + if (!str) + return -1; - strcpy(str, DUMMY_MSG); - named_val->u.val_str = str; - break; - } + strcpy(str, DUMMY_MSG); + named_val->u.val_str = str; + break; + } default: break; } diff --git a/mali_kbase/tests/kutf/kutf_kprobe.c b/mali_kbase/tests/kutf/kutf_kprobe.c new file mode 100644 index 0000000..f118692 --- /dev/null +++ b/mali_kbase/tests/kutf/kutf_kprobe.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note +/* + * + * (C) COPYRIGHT 2023 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation, and any use by you of this program is subject to the terms + * of such GNU license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + */ + +/* Kernel probe functionality. + */ + +#ifdef CONFIG_KPROBES + +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/debugfs.h> +#include <linux/kprobes.h> +#include <linux/version.h> +#include <kutf/kutf_kprobe.h> + +#define KUTF_KP_REG_MIN_ARGS 3 +#define KUTF_KP_UNREG_MIN_ARGS 2 +#define KUTF_KP_FUNC_NAME_ARG 0 +#define KUTF_KP_FUNC_ENTRY_EXIT_ARG 1 +#define KUTF_KP_FUNC_HANDLER_ARG 2 + +#define KUTF_KP_WRITE_BUFSIZE 4096 + +/* Stores address to kernel function 'kallsyms_lookup_name' + * as 'kallsyms_lookup_name' is no longer exported from 5.7 kernel. + */ +typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); +kallsyms_lookup_name_t kutf_ksym_lookup_name; + +static ssize_t kutf_kp_reg_debugfs_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos); + +static ssize_t kutf_kp_unreg_debugfs_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos); + +static LIST_HEAD(kp_list); +static DEFINE_MUTEX(kp_list_lock); + +/** + * struct kutf_kp_data - Structure which holds data per kprobe instance + * @kretp: reference to kernel ret probe + * @entry: true if this probe is for function entry.Otherwise it is exit. + * @argc: Number of arguments to be passed to probe handler + * @argv: arguments passed to probe handler + * @kp_handler: Actual handler which is called when probe is triggered + * @list: node for adding to kp_list + */ +struct kutf_kp_data { + struct kretprobe kretp; + bool entry; + int argc; + char **argv; + kutf_kp_handler kp_handler; + struct list_head list; +}; + +const struct file_operations kutf_kp_reg_debugfs_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = kutf_kp_reg_debugfs_write, +}; + +const struct file_operations kutf_kp_unreg_debugfs_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = kutf_kp_unreg_debugfs_write, +}; + +struct kprobe kutf_kallsym_kp = { .symbol_name = "kallsyms_lookup_name" }; + +void kutf_kp_sample_kernel_function(void) +{ + pr_debug("%s called\n", __func__); +} +EXPORT_SYMBOL(kutf_kp_sample_kernel_function); + +void kutf_kp_sample_handler(int argc, char **argv) +{ + int i = 0; + + for (; i < argc; i++) + pr_info("%s %s\n", __func__, argv[i]); +} +EXPORT_SYMBOL(kutf_kp_sample_handler); + +static int kutf_call_kp_handler(struct kretprobe *p) +{ + struct kutf_kp_data *kp_p; + kutf_kp_handler kp_handler; + + kp_p = (struct kutf_kp_data *)p; + kp_handler = kp_p->kp_handler; + + if (kp_handler) { + /* Arguments to registered handler starts after + * KUTF_KP_REG_MIN_ARGS. + */ + (*kp_handler)((kp_p->argc) - KUTF_KP_REG_MIN_ARGS, + &(kp_p->argv[KUTF_KP_REG_MIN_ARGS])); + } + return 0; +} + +static int kutf_kretp_handler(struct kretprobe_instance *ri, struct pt_regs *regs) +{ +#if (KERNEL_VERSION(5, 11, 0) <= LINUX_VERSION_CODE) + return kutf_call_kp_handler(ri->rph->rp); +#else + return kutf_call_kp_handler(ri->rp); +#endif +} + +static kutf_kp_handler kutf_get_kp_handler(char **argv) +{ + if ((NULL == argv) || (NULL == kutf_ksym_lookup_name)) + return NULL; + + return (kutf_kp_handler)((*kutf_ksym_lookup_name)(argv[KUTF_KP_FUNC_HANDLER_ARG])); +} + +static ssize_t kutf_kp_reg_debugfs_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + int argc = 0; + int ret = count; + char **argv; + char *kbuf; + char *func_name; + struct kutf_kp_data *kp_p; + struct kutf_kp_data *kp_iter; + + if (count >= KUTF_KP_WRITE_BUFSIZE) + return -EINVAL; + + kbuf = memdup_user(user_buf, count); + if (IS_ERR(kbuf)) { + return -ENOMEM; + } + kbuf[count - 1] = '\0'; + + argv = argv_split(GFP_KERNEL, kbuf, &argc); + if (!argv) { + ret = -ENOMEM; + goto out; + } + if (argc < KUTF_KP_REG_MIN_ARGS) { + pr_debug("Insufficient args in reg kprobe:%d\n", argc); + ret = -EINVAL; + goto argv_out; + } + + kp_p = kzalloc(sizeof(struct kutf_kp_data), GFP_KERNEL); + if (!kp_p) + goto argv_out; + + if (!(strcmp(argv[KUTF_KP_FUNC_ENTRY_EXIT_ARG], "entry"))) { + kp_p->kretp.entry_handler = kutf_kretp_handler; + kp_p->entry = 1; + } else if (!(strcmp(argv[KUTF_KP_FUNC_ENTRY_EXIT_ARG], "exit"))) { + kp_p->kretp.handler = kutf_kretp_handler; + } else { + pr_err("Invalid arg:%s passed in reg kprobe\n", argv[KUTF_KP_FUNC_ENTRY_EXIT_ARG]); + ret = -EINVAL; + kfree(kp_p); + goto argv_out; + } + + func_name = argv[KUTF_KP_FUNC_NAME_ARG]; + + mutex_lock(&kp_list_lock); + list_for_each_entry(kp_iter, &kp_list, list) { + if ((kp_iter->entry == kp_p->entry) && + (!(strcmp(kp_iter->kretp.kp.symbol_name, func_name)))) { + ret = -EEXIST; + kfree(kp_p); + mutex_unlock(&kp_list_lock); + goto argv_out; + } + } + + kp_p->kretp.kp.symbol_name = func_name; + kp_p->kp_handler = kutf_get_kp_handler(argv); + if (!(kp_p->kp_handler)) { + pr_debug("cannot find addr for handler:%s\n", argv[KUTF_KP_FUNC_HANDLER_ARG]); + ret = -EINVAL; + kfree(kp_p); + mutex_unlock(&kp_list_lock); + goto argv_out; + } + kp_p->argc = argc; + kp_p->argv = argv; + ret = register_kretprobe(&kp_p->kretp); + if (ret) { + ret = -EINVAL; + kfree(kp_p); + mutex_unlock(&kp_list_lock); + goto argv_out; + } + INIT_LIST_HEAD(&kp_p->list); + list_add(&kp_p->list, &kp_list); + + mutex_unlock(&kp_list_lock); + + ret = count; + goto out; + +argv_out: + argv_free(argv); + +out: + kfree(kbuf); + + return ret; +} + +static ssize_t kutf_kp_unreg_debugfs_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + int argc = 0; + int ret = -EINVAL; + char **argv = NULL; + char *kbuf; + char *func_name; + struct kutf_kp_data *kp_iter; + bool entry; + + if (count >= KUTF_KP_WRITE_BUFSIZE) + return -EINVAL; + + kbuf = memdup_user(user_buf, count); + if (IS_ERR(kbuf)) { + return -ENOMEM; + } + kbuf[count - 1] = '\0'; + + argv = argv_split(GFP_KERNEL, kbuf, &argc); + if (!argv) { + ret = -ENOMEM; + goto out; + } + if (argc < KUTF_KP_UNREG_MIN_ARGS) { + pr_debug("Insufficient args in unreg kprobe:%d\n", argc); + ret = -EINVAL; + goto out; + } + if (!(strcmp(argv[KUTF_KP_FUNC_ENTRY_EXIT_ARG], "entry"))) + entry = 1; + else if (!(strcmp(argv[KUTF_KP_FUNC_ENTRY_EXIT_ARG], "exit"))) + entry = 0; + else { + pr_err("Invalid arg:%s passed in unreg kprobe\n", + argv[KUTF_KP_FUNC_ENTRY_EXIT_ARG]); + ret = -EINVAL; + goto out; + } + func_name = argv[KUTF_KP_FUNC_NAME_ARG]; + + mutex_lock(&kp_list_lock); + list_for_each_entry(kp_iter, &kp_list, list) { + if ((kp_iter->entry == entry) && + (!(strcmp(func_name, kp_iter->kretp.kp.symbol_name)))) { + unregister_kretprobe(&kp_iter->kretp); + argv_free(kp_iter->argv); + list_del(&kp_iter->list); + kfree(kp_iter); + ret = count; + break; + } + } + mutex_unlock(&kp_list_lock); +out: + argv_free(argv); + kfree(kbuf); + + return ret; +} + +int __init kutf_kprobe_init(struct dentry *base_dir) +{ + struct dentry *kutf_kp_reg_debugfs_file; + struct dentry *kutf_kp_unreg_debugfs_file; + + if (!(register_kprobe(&kutf_kallsym_kp))) { + /* After kernel 5.7, 'kallsyms_lookup_name' is no longer + * exported. So we need this workaround to get the + * addr of 'kallsyms_lookup_name'. This will be used later + * in kprobe handler function to call the registered + * handler for a probe from the name passed from userspace. + */ + kutf_ksym_lookup_name = (kallsyms_lookup_name_t)kutf_kallsym_kp.addr; + unregister_kprobe(&kutf_kallsym_kp); + kutf_kp_reg_debugfs_file = debugfs_create_file("register_kprobe", 0200, base_dir, + NULL, &kutf_kp_reg_debugfs_fops); + if (IS_ERR_OR_NULL(kutf_kp_reg_debugfs_file)) + pr_err("Failed to create kprobe reg debugfs file"); + + kutf_kp_unreg_debugfs_file = debugfs_create_file( + "unregister_kprobe", 0200, base_dir, NULL, &kutf_kp_unreg_debugfs_fops); + if (IS_ERR_OR_NULL(kutf_kp_unreg_debugfs_file)) { + pr_err("Failed to create kprobe unreg debugfs file"); + debugfs_remove(kutf_kp_reg_debugfs_file); + } + } else + pr_info("kallsyms_lookup_name addr not available\n"); + + return 0; +} + +void kutf_kprobe_exit(void) +{ + struct kutf_kp_data *kp_iter; + struct kutf_kp_data *n; + + mutex_lock(&kp_list_lock); + + list_for_each_entry_safe(kp_iter, n, &kp_list, list) { + unregister_kretprobe(&kp_iter->kretp); + argv_free(kp_iter->argv); + list_del(&kp_iter->list); + kfree(kp_iter); + } + + mutex_unlock(&kp_list_lock); +} + +#endif diff --git a/mali_kbase/tests/kutf/kutf_mem.c b/mali_kbase/tests/kutf/kutf_mem.c index 716970a..527ddaa 100644 --- a/mali_kbase/tests/kutf/kutf_mem.c +++ b/mali_kbase/tests/kutf/kutf_mem.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014, 2017, 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -27,7 +27,6 @@ #include <kutf/kutf_mem.h> - /** * struct kutf_alloc_entry - Structure representing an allocation. * @node: List node for use with kutf_mempool. @@ -71,7 +70,6 @@ void kutf_mempool_destroy(struct kutf_mempool *pool) kfree(remove_alloc); } mutex_unlock(&pool->lock); - } EXPORT_SYMBOL(kutf_mempool_destroy); diff --git a/mali_kbase/tests/kutf/kutf_resultset.c b/mali_kbase/tests/kutf/kutf_resultset.c index 3a7ade2..4f62d04 100644 --- a/mali_kbase/tests/kutf/kutf_resultset.c +++ b/mali_kbase/tests/kutf/kutf_resultset.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014, 2017, 2020-2021 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -54,9 +54,8 @@ fail_alloc: return NULL; } -int kutf_add_result(struct kutf_context *context, - enum kutf_result_status status, - const char *message) +int kutf_add_result(struct kutf_context *context, enum kutf_result_status status, + const char *message) { struct kutf_mempool *mempool = &context->fixture_pool; struct kutf_result_set *set = context->result_set; @@ -115,8 +114,7 @@ struct kutf_result *kutf_remove_result(struct kutf_result_set *set) int ret; do { - ret = wait_event_interruptible(set->waitq, - kutf_has_result(set)); + ret = wait_event_interruptible(set->waitq, kutf_has_result(set)); if (ret) return ERR_PTR(ret); @@ -124,15 +122,11 @@ struct kutf_result *kutf_remove_result(struct kutf_result_set *set) spin_lock(&kutf_result_lock); if (!list_empty(&set->results)) { - result = list_first_entry(&set->results, - struct kutf_result, - node); + result = list_first_entry(&set->results, struct kutf_result, node); list_del(&result->node); } else if (set->flags & KUTF_RESULT_SET_WAITING_FOR_INPUT) { /* Return a fake result */ - static struct kutf_result waiting = { - .status = KUTF_RESULT_USERDATA_WAIT - }; + static struct kutf_result waiting = { .status = KUTF_RESULT_USERDATA_WAIT }; result = &waiting; } /* If result == NULL then there was a race with the event diff --git a/mali_kbase/tests/kutf/kutf_suite.c b/mali_kbase/tests/kutf/kutf_suite.c index 4468066..dcd4cb3 100644 --- a/mali_kbase/tests/kutf/kutf_suite.c +++ b/mali_kbase/tests/kutf/kutf_suite.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014, 2017-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -33,13 +33,15 @@ #include <linux/version.h> #include <linux/atomic.h> #include <linux/sched.h> - #include <generated/autoconf.h> #include <kutf/kutf_suite.h> #include <kutf/kutf_resultset.h> #include <kutf/kutf_utils.h> #include <kutf/kutf_helpers.h> +#ifdef CONFIG_KPROBES +#include <kutf/kutf_kprobe.h> +#endif /** * struct kutf_application - Structure which represents kutf application @@ -49,9 +51,9 @@ * application */ struct kutf_application { - const char *name; - struct dentry *dir; - struct list_head suite_list; + const char *name; + struct dentry *dir; + struct list_head suite_list; }; /** @@ -68,14 +70,14 @@ struct kutf_application { * @dir: debugfs directory for this test function */ struct kutf_test_function { - struct kutf_suite *suite; - unsigned int filters; - unsigned int test_id; + struct kutf_suite *suite; + unsigned int filters; + unsigned int test_id; void (*execute)(struct kutf_context *context); union kutf_callback_data test_data; - struct list_head node; - struct list_head variant_list; - struct dentry *dir; + struct list_head node; + struct list_head variant_list; + struct dentry *dir; }; /** @@ -88,9 +90,9 @@ struct kutf_test_function { */ struct kutf_test_fixture { struct kutf_test_function *test_func; - unsigned int fixture_index; - struct list_head node; - struct dentry *dir; + unsigned int fixture_index; + struct list_head node; + struct dentry *dir; }; static struct dentry *base_dir; @@ -102,14 +104,14 @@ static struct workqueue_struct *kutf_workq; * @result: Status value for a single test */ struct kutf_convert_table { - char result_name[50]; + char result_name[50]; enum kutf_result_status result; }; static const struct kutf_convert_table kutf_convert[] = { -#define ADD_UTF_RESULT(_name) \ - { \ -#_name, _name, \ +#define ADD_UTF_RESULT(_name) \ + { \ +#_name, _name, \ } ADD_UTF_RESULT(KUTF_RESULT_BENCHMARK), ADD_UTF_RESULT(KUTF_RESULT_SKIP), ADD_UTF_RESULT(KUTF_RESULT_UNKNOWN), ADD_UTF_RESULT(KUTF_RESULT_PASS), @@ -130,8 +132,7 @@ static const struct kutf_convert_table kutf_convert[] = { * * Return: Returns the created test context on success or NULL on failure */ -static struct kutf_context *kutf_create_context( - struct kutf_test_fixture *test_fix); +static struct kutf_context *kutf_create_context(struct kutf_test_fixture *test_fix); /** * kutf_destroy_context() - Destroy a previously created test context, only @@ -166,8 +167,7 @@ static void kutf_context_put(struct kutf_context *context); * @context: Test context * @status: Result status */ -static void kutf_set_result(struct kutf_context *context, - enum kutf_result_status status); +static void kutf_set_result(struct kutf_context *context, enum kutf_result_status status); /** * kutf_set_expected_result() - Set the expected test result for the specified @@ -176,7 +176,7 @@ static void kutf_set_result(struct kutf_context *context, * @expected_status: Expected result status */ static void kutf_set_expected_result(struct kutf_context *context, - enum kutf_result_status expected_status); + enum kutf_result_status expected_status); /** * kutf_result_to_string() - Converts a KUTF result into a string @@ -187,7 +187,7 @@ static void kutf_set_expected_result(struct kutf_context *context, */ static int kutf_result_to_string(const char **result_str, enum kutf_result_status result) { - int i; + size_t i; int ret = 0; for (i = 0; i < UTF_CONVERT_SIZE; i++) { @@ -210,8 +210,8 @@ static int kutf_result_to_string(const char **result_str, enum kutf_result_statu * Return: On success, the number of bytes read and offset @ppos advanced by * this number; on error, negative value */ -static ssize_t kutf_debugfs_const_string_read(struct file *file, - char __user *buf, size_t len, loff_t *ppos) +static ssize_t kutf_debugfs_const_string_read(struct file *file, char __user *buf, size_t len, + loff_t *ppos) { char *str = file->private_data; @@ -222,7 +222,7 @@ static const struct file_operations kutf_debugfs_const_string_ops = { .owner = THIS_MODULE, .open = simple_open, .read = kutf_debugfs_const_string_read, - .llseek = default_llseek, + .llseek = default_llseek, }; /** @@ -237,41 +237,33 @@ static void kutf_add_explicit_result(struct kutf_context *context) case KUTF_RESULT_WARN: if (context->status == KUTF_RESULT_WARN) - kutf_test_pass(context, - "Pass (expected warn occurred)"); + kutf_test_pass(context, "Pass (expected warn occurred)"); else if (context->status != KUTF_RESULT_SKIP) - kutf_test_fail(context, - "Fail (expected warn missing)"); + kutf_test_fail(context, "Fail (expected warn missing)"); break; case KUTF_RESULT_FAIL: if (context->status == KUTF_RESULT_FAIL) - kutf_test_pass(context, - "Pass (expected fail occurred)"); + kutf_test_pass(context, "Pass (expected fail occurred)"); else if (context->status != KUTF_RESULT_SKIP) { /* Force the expected status so the fail gets logged */ context->expected_status = KUTF_RESULT_PASS; - kutf_test_fail(context, - "Fail (expected fail missing)"); + kutf_test_fail(context, "Fail (expected fail missing)"); } break; case KUTF_RESULT_FATAL: if (context->status == KUTF_RESULT_FATAL) - kutf_test_pass(context, - "Pass (expected fatal occurred)"); + kutf_test_pass(context, "Pass (expected fatal occurred)"); else if (context->status != KUTF_RESULT_SKIP) - kutf_test_fail(context, - "Fail (expected fatal missing)"); + kutf_test_fail(context, "Fail (expected fatal missing)"); break; case KUTF_RESULT_ABORT: if (context->status == KUTF_RESULT_ABORT) - kutf_test_pass(context, - "Pass (expected abort occurred)"); + kutf_test_pass(context, "Pass (expected abort occurred)"); else if (context->status != KUTF_RESULT_SKIP) - kutf_test_fail(context, - "Fail (expected abort missing)"); + kutf_test_fail(context, "Fail (expected abort missing)"); break; default: break; @@ -280,8 +272,7 @@ static void kutf_add_explicit_result(struct kutf_context *context) static void kutf_run_test(struct work_struct *data) { - struct kutf_context *test_context = container_of(data, - struct kutf_context, work); + struct kutf_context *test_context = container_of(data, struct kutf_context, work); struct kutf_suite *suite = test_context->suite; struct kutf_test_function *test_func; @@ -295,10 +286,13 @@ static void kutf_run_test(struct work_struct *data) test_context->fixture = suite->create_fixture(test_context); /* Only run the test if the fixture was created (if required) */ - if ((suite->create_fixture && test_context->fixture) || - (!suite->create_fixture)) { - /* Run this fixture */ - test_func->execute(test_context); + if ((suite->create_fixture && test_context->fixture) || (!suite->create_fixture)) { + if (test_func->filters & KUTF_F_TEST_EXPECTED_FAILURE) { + kutf_test_fail(test_context, + "KUTF: Test marked as 'Expected Failure' not run."); + } else { + test_func->execute(test_context); + } if (suite->remove_fixture) suite->remove_fixture(test_context); @@ -368,8 +362,7 @@ finish: * * Return: Number of bytes read. */ -static ssize_t kutf_debugfs_run_read(struct file *file, char __user *buf, - size_t len, loff_t *ppos) +static ssize_t kutf_debugfs_run_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { struct kutf_context *test_context = file->private_data; struct kutf_result *res; @@ -394,8 +387,7 @@ static ssize_t kutf_debugfs_run_read(struct file *file, char __user *buf, case KUTF_RESULT_TEST_FINISHED: return 0; case KUTF_RESULT_USERDATA_WAIT: - if (test_context->userdata.flags & - KUTF_USERDATA_WARNING_OUTPUT) { + if (test_context->userdata.flags & KUTF_USERDATA_WARNING_OUTPUT) { /* * Warning message already output, * signal end-of-file @@ -403,37 +395,33 @@ static ssize_t kutf_debugfs_run_read(struct file *file, char __user *buf, return 0; } - message_len = sizeof(USERDATA_WARNING_MESSAGE)-1; + message_len = sizeof(USERDATA_WARNING_MESSAGE) - 1; if (message_len > len) message_len = len; - bytes_not_copied = copy_to_user(buf, - USERDATA_WARNING_MESSAGE, - message_len); + bytes_not_copied = copy_to_user(buf, USERDATA_WARNING_MESSAGE, message_len); if (bytes_not_copied != 0) return -EFAULT; test_context->userdata.flags |= KUTF_USERDATA_WARNING_OUTPUT; - return message_len; + return (ssize_t)message_len; case KUTF_RESULT_USERDATA: message_len = strlen(res->message); - if (message_len > len-1) { - message_len = len-1; + if (message_len > len - 1) { + message_len = len - 1; pr_warn("User data truncated, read not long enough\n"); } - bytes_not_copied = copy_to_user(buf, res->message, - message_len); + bytes_not_copied = copy_to_user(buf, res->message, message_len); if (bytes_not_copied != 0) { pr_warn("Failed to copy data to user space buffer\n"); return -EFAULT; } /* Finally the terminator */ - bytes_not_copied = copy_to_user(&buf[message_len], - &terminator, 1); + bytes_not_copied = copy_to_user(&buf[message_len], &terminator, 1); if (bytes_not_copied != 0) { pr_warn("Failed to copy data to user space buffer\n"); return -EFAULT; } - return message_len+1; + return (ssize_t)message_len + 1; default: /* Fall through - this is a test result */ break; @@ -454,33 +442,29 @@ static ssize_t kutf_debugfs_run_read(struct file *file, char __user *buf, /* First copy the result string */ if (kutf_str_ptr) { - bytes_not_copied = copy_to_user(&buf[0], kutf_str_ptr, - kutf_str_len); - bytes_copied += kutf_str_len - bytes_not_copied; + bytes_not_copied = copy_to_user(&buf[0], kutf_str_ptr, kutf_str_len); + bytes_copied += (ssize_t)(kutf_str_len - bytes_not_copied); if (bytes_not_copied) goto exit; } /* Then the separator */ - bytes_not_copied = copy_to_user(&buf[bytes_copied], - &separator, 1); - bytes_copied += 1 - bytes_not_copied; + bytes_not_copied = copy_to_user(&buf[bytes_copied], &separator, 1); + bytes_copied += (ssize_t)(1 - bytes_not_copied); if (bytes_not_copied) goto exit; /* Finally Next copy the result string */ if (res->message) { - bytes_not_copied = copy_to_user(&buf[bytes_copied], - res->message, message_len); - bytes_copied += message_len - bytes_not_copied; + bytes_not_copied = copy_to_user(&buf[bytes_copied], res->message, message_len); + bytes_copied += (ssize_t)(message_len - bytes_not_copied); if (bytes_not_copied) goto exit; } /* Finally the terminator */ - bytes_not_copied = copy_to_user(&buf[bytes_copied], - &terminator, 1); - bytes_copied += 1 - bytes_not_copied; + bytes_not_copied = copy_to_user(&buf[bytes_copied], &terminator, 1); + bytes_copied += (ssize_t)(1 - bytes_not_copied); exit: return bytes_copied; @@ -500,8 +484,8 @@ exit: * * Return: Number of bytes written */ -static ssize_t kutf_debugfs_run_write(struct file *file, - const char __user *buf, size_t len, loff_t *ppos) +static ssize_t kutf_debugfs_run_write(struct file *file, const char __user *buf, size_t len, + loff_t *ppos) { int ret = 0; struct kutf_context *test_context = file->private_data; @@ -513,7 +497,7 @@ static ssize_t kutf_debugfs_run_write(struct file *file, if (ret < 0) return ret; - return len; + return (ssize_t)len; } /** @@ -544,7 +528,7 @@ static const struct file_operations kutf_debugfs_run_ops = { .read = kutf_debugfs_run_read, .write = kutf_debugfs_run_write, .release = kutf_debugfs_run_release, - .llseek = default_llseek, + .llseek = default_llseek, }; /** @@ -556,11 +540,10 @@ static const struct file_operations kutf_debugfs_run_ops = { * * Return: 0 on success, negative value corresponding to error code in failure */ -static int create_fixture_variant(struct kutf_test_function *test_func, - unsigned int fixture_index) +static int create_fixture_variant(struct kutf_test_function *test_func, unsigned int fixture_index) { struct kutf_test_fixture *test_fix; - char name[11]; /* Enough to print the MAX_UINT32 + the null terminator */ + char name[11]; /* Enough to print the MAX_UINT32 + the null terminator */ struct dentry *tmp; int err; @@ -592,10 +575,8 @@ static int create_fixture_variant(struct kutf_test_function *test_func, goto fail_file; } - tmp = debugfs_create_file_unsafe( - "run", 0600, test_fix->dir, - test_fix, - &kutf_debugfs_run_ops); + tmp = debugfs_create_file_unsafe("run", 0600, test_fix->dir, test_fix, + &kutf_debugfs_run_ops); if (IS_ERR_OR_NULL(tmp)) { pr_err("Failed to create debugfs file \"run\" when adding fixture\n"); /* Might not be the right error, we don't get it passed back to us */ @@ -635,13 +616,10 @@ static int ktufp_u32_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(kutfp_fops_x32_ro, ktufp_u32_get, NULL, "0x%08llx\n"); #endif -void kutf_add_test_with_filters_and_data( - struct kutf_suite *suite, - unsigned int id, - const char *name, - void (*execute)(struct kutf_context *context), - unsigned int filters, - union kutf_callback_data test_data) +void kutf_add_test_with_filters_and_data(struct kutf_suite *suite, unsigned int id, + const char *name, + void (*execute)(struct kutf_context *context), + unsigned int filters, union kutf_callback_data test_data) { struct kutf_test_function *test_func; struct dentry *tmp; @@ -670,11 +648,10 @@ void kutf_add_test_with_filters_and_data( test_func->filters = filters; #if KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE - tmp = debugfs_create_file_unsafe("filters", 0004, test_func->dir, - &test_func->filters, &kutfp_fops_x32_ro); + tmp = debugfs_create_file_unsafe("filters", 0004, test_func->dir, &test_func->filters, + &kutfp_fops_x32_ro); #else - tmp = debugfs_create_x32("filters", 0004, test_func->dir, - &test_func->filters); + tmp = debugfs_create_x32("filters", 0004, test_func->dir, &test_func->filters); #endif if (IS_ERR_OR_NULL(tmp)) { pr_err("Failed to create debugfs file \"filters\" when adding test %s\n", name); @@ -683,11 +660,9 @@ void kutf_add_test_with_filters_and_data( test_func->test_id = id; #if KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE - debugfs_create_u32("test_id", 0004, test_func->dir, - &test_func->test_id); + debugfs_create_u32("test_id", 0004, test_func->dir, &test_func->test_id); #else - tmp = debugfs_create_u32("test_id", 0004, test_func->dir, - &test_func->test_id); + tmp = debugfs_create_u32("test_id", 0004, test_func->dir, &test_func->test_id); if (IS_ERR_OR_NULL(tmp)) { pr_err("Failed to create debugfs file \"test_id\" when adding test %s\n", name); goto fail_file; @@ -717,40 +692,26 @@ fail_alloc: } EXPORT_SYMBOL(kutf_add_test_with_filters_and_data); -void kutf_add_test_with_filters( - struct kutf_suite *suite, - unsigned int id, - const char *name, - void (*execute)(struct kutf_context *context), - unsigned int filters) +void kutf_add_test_with_filters(struct kutf_suite *suite, unsigned int id, const char *name, + void (*execute)(struct kutf_context *context), unsigned int filters) { union kutf_callback_data data; data.ptr_value = NULL; - kutf_add_test_with_filters_and_data(suite, - id, - name, - execute, - suite->suite_default_flags, - data); + kutf_add_test_with_filters_and_data(suite, id, name, execute, + suite->suite_default_flags & filters, data); } EXPORT_SYMBOL(kutf_add_test_with_filters); -void kutf_add_test(struct kutf_suite *suite, - unsigned int id, - const char *name, - void (*execute)(struct kutf_context *context)) +void kutf_add_test(struct kutf_suite *suite, unsigned int id, const char *name, + void (*execute)(struct kutf_context *context)) { union kutf_callback_data data; data.ptr_value = NULL; - kutf_add_test_with_filters_and_data(suite, - id, - name, - execute, - suite->suite_default_flags, + kutf_add_test_with_filters_and_data(suite, id, name, execute, suite->suite_default_flags, data); } EXPORT_SYMBOL(kutf_add_test); @@ -776,14 +737,12 @@ static void kutf_remove_test(struct kutf_test_function *test_func) kfree(test_func); } -struct kutf_suite *kutf_create_suite_with_filters_and_data( - struct kutf_application *app, - const char *name, - unsigned int fixture_count, - void *(*create_fixture)(struct kutf_context *context), - void (*remove_fixture)(struct kutf_context *context), - unsigned int filters, - union kutf_callback_data suite_data) +struct kutf_suite * +kutf_create_suite_with_filters_and_data(struct kutf_application *app, const char *name, + unsigned int fixture_count, + void *(*create_fixture)(struct kutf_context *context), + void (*remove_fixture)(struct kutf_context *context), + unsigned int filters, union kutf_callback_data suite_data) { struct kutf_suite *suite; struct dentry *tmp; @@ -830,43 +789,28 @@ fail_kmalloc: EXPORT_SYMBOL(kutf_create_suite_with_filters_and_data); struct kutf_suite *kutf_create_suite_with_filters( - struct kutf_application *app, - const char *name, - unsigned int fixture_count, - void *(*create_fixture)(struct kutf_context *context), - void (*remove_fixture)(struct kutf_context *context), - unsigned int filters) + struct kutf_application *app, const char *name, unsigned int fixture_count, + void *(*create_fixture)(struct kutf_context *context), + void (*remove_fixture)(struct kutf_context *context), unsigned int filters) { union kutf_callback_data data; data.ptr_value = NULL; - return kutf_create_suite_with_filters_and_data(app, - name, - fixture_count, - create_fixture, - remove_fixture, - filters, - data); + return kutf_create_suite_with_filters_and_data(app, name, fixture_count, create_fixture, + remove_fixture, filters, data); } EXPORT_SYMBOL(kutf_create_suite_with_filters); -struct kutf_suite *kutf_create_suite( - struct kutf_application *app, - const char *name, - unsigned int fixture_count, - void *(*create_fixture)(struct kutf_context *context), - void (*remove_fixture)(struct kutf_context *context)) +struct kutf_suite *kutf_create_suite(struct kutf_application *app, const char *name, + unsigned int fixture_count, + void *(*create_fixture)(struct kutf_context *context), + void (*remove_fixture)(struct kutf_context *context)) { union kutf_callback_data data; data.ptr_value = NULL; - return kutf_create_suite_with_filters_and_data(app, - name, - fixture_count, - create_fixture, - remove_fixture, - KUTF_F_TEST_GENERIC, - data); + return kutf_create_suite_with_filters_and_data(app, name, fixture_count, create_fixture, + remove_fixture, KUTF_F_TEST_GENERIC, data); } EXPORT_SYMBOL(kutf_create_suite); @@ -911,7 +855,8 @@ struct kutf_application *kutf_create_application(const char *name) tmp = debugfs_create_file("type", 0004, app->dir, "application\n", &kutf_debugfs_const_string_ops); if (IS_ERR_OR_NULL(tmp)) { - pr_err("Failed to create debugfs file \"type\" when creating application %s\n", name); + pr_err("Failed to create debugfs file \"type\" when creating application %s\n", + name); goto fail_file; } @@ -946,15 +891,14 @@ void kutf_destroy_application(struct kutf_application *app) } EXPORT_SYMBOL(kutf_destroy_application); -static struct kutf_context *kutf_create_context( - struct kutf_test_fixture *test_fix) +static struct kutf_context *kutf_create_context(struct kutf_test_fixture *test_fix) { struct kutf_context *new_context; new_context = kmalloc(sizeof(*new_context), GFP_KERNEL); if (!new_context) { pr_err("Failed to allocate test context"); - goto fail_alloc; + goto fail_context_alloc; } new_context->result_set = kutf_create_result_set(); @@ -975,6 +919,8 @@ static struct kutf_context *kutf_create_context( new_context->fixture_name = NULL; new_context->test_data = test_fix->test_func->test_data; + mutex_init(&new_context->output_sync); + new_context->userdata.flags = 0; INIT_LIST_HEAD(&new_context->userdata.input_head); init_waitqueue_head(&new_context->userdata.input_waitq); @@ -987,7 +933,7 @@ static struct kutf_context *kutf_create_context( fail_result_set: kfree(new_context); -fail_alloc: +fail_context_alloc: return NULL; } @@ -1011,15 +957,13 @@ static void kutf_context_put(struct kutf_context *context) kref_put(&context->kref, kutf_destroy_context); } - -static void kutf_set_result(struct kutf_context *context, - enum kutf_result_status status) +static void kutf_set_result(struct kutf_context *context, enum kutf_result_status status) { context->status = status; } static void kutf_set_expected_result(struct kutf_context *context, - enum kutf_result_status expected_status) + enum kutf_result_status expected_status) { context->expected_status = expected_status; } @@ -1030,10 +974,8 @@ static void kutf_set_expected_result(struct kutf_context *context, * @message: Result string * @new_status: Result status */ -static void kutf_test_log_result( - struct kutf_context *context, - const char *message, - enum kutf_result_status new_status) +static void kutf_test_log_result(struct kutf_context *context, const char *message, + enum kutf_result_status new_status) { if (context->status < new_status) context->status = new_status; @@ -1042,10 +984,8 @@ static void kutf_test_log_result( kutf_add_result(context, new_status, message); } -void kutf_test_log_result_external( - struct kutf_context *context, - const char *message, - enum kutf_result_status new_status) +void kutf_test_log_result_external(struct kutf_context *context, const char *message, + enum kutf_result_status new_status) { kutf_test_log_result(context, message, new_status); } @@ -1095,8 +1035,9 @@ void kutf_test_skip_msg(struct kutf_context *context, const char *message) kutf_set_result(context, KUTF_RESULT_SKIP); kutf_set_expected_result(context, KUTF_RESULT_UNKNOWN); - kutf_test_log_result(context, kutf_dsprintf(&context->fixture_pool, - "Test skipped: %s", message), KUTF_RESULT_SKIP); + kutf_test_log_result(context, + kutf_dsprintf(&context->fixture_pool, "Test skipped: %s", message), + KUTF_RESULT_SKIP); kutf_test_log_result(context, "!!!Test skipped!!!", KUTF_RESULT_SKIP); } EXPORT_SYMBOL(kutf_test_skip_msg); @@ -1124,6 +1065,20 @@ void kutf_test_info(struct kutf_context *context, char const *message) } EXPORT_SYMBOL(kutf_test_info); +__printf(2, 3) void kutf_test_info_msg(struct kutf_context *context, char const *msg, ...) +{ + va_list args; + + mutex_lock(&context->output_sync); + + va_start(args, msg); + kutf_test_info(context, kutf_dsprintf(&context->fixture_pool, msg, args)); + va_end(args); + + mutex_unlock(&context->output_sync); +} +EXPORT_SYMBOL(kutf_test_info_msg); + void kutf_test_warn(struct kutf_context *context, char const *message) { kutf_test_log_result(context, message, KUTF_RESULT_WARN); @@ -1136,6 +1091,20 @@ void kutf_test_fail(struct kutf_context *context, char const *message) } EXPORT_SYMBOL(kutf_test_fail); +__printf(2, 3) void kutf_test_fail_msg(struct kutf_context *context, char const *msg, ...) +{ + va_list args; + + mutex_lock(&context->output_sync); + + va_start(args, msg); + kutf_test_fail(context, kutf_dsprintf(&context->fixture_pool, msg, args)); + va_end(args); + + mutex_unlock(&context->output_sync); +} +EXPORT_SYMBOL(kutf_test_fail_msg); + void kutf_test_fatal(struct kutf_context *context, char const *message) { kutf_test_log_result(context, message, KUTF_RESULT_FATAL); @@ -1169,6 +1138,10 @@ static int __init init_kutf_core(void) return -ENOMEM; } +#ifdef CONFIG_KPROBES + kutf_kprobe_init(base_dir); +#endif + return 0; } @@ -1179,13 +1152,16 @@ static int __init init_kutf_core(void) */ static void __exit exit_kutf_core(void) { +#ifdef CONFIG_KPROBES + kutf_kprobe_exit(); +#endif debugfs_remove_recursive(base_dir); if (kutf_workq) destroy_workqueue(kutf_workq); } -#else /* CONFIG_DEBUG_FS */ +#else /* CONFIG_DEBUG_FS */ /** * init_kutf_core - Module entry point @@ -1208,7 +1184,7 @@ static int __init init_kutf_core(void) static void __exit exit_kutf_core(void) { } -#endif /* CONFIG_DEBUG_FS */ +#endif /* CONFIG_DEBUG_FS */ MODULE_LICENSE("GPL"); diff --git a/mali_kbase/tests/kutf/kutf_utils.c b/mali_kbase/tests/kutf/kutf_utils.c index 21f5fad..183ab36 100644 --- a/mali_kbase/tests/kutf/kutf_utils.c +++ b/mali_kbase/tests/kutf/kutf_utils.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note /* * - * (C) COPYRIGHT 2014, 2017, 2020-2022 ARM Limited. All rights reserved. + * (C) COPYRIGHT 2014-2023 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software @@ -33,12 +33,11 @@ static char tmp_buffer[KUTF_MAX_DSPRINTF_LEN]; static DEFINE_MUTEX(buffer_lock); -const char *kutf_dsprintf(struct kutf_mempool *pool, - const char *fmt, ...) +const char *kutf_dsprintf(struct kutf_mempool *pool, const char *fmt, ...) { va_list args; int len; - int size; + size_t size; void *buffer; mutex_lock(&buffer_lock); @@ -51,11 +50,11 @@ const char *kutf_dsprintf(struct kutf_mempool *pool, goto fail_format; } - if (len >= sizeof(tmp_buffer)) { + if (len >= (int)sizeof(tmp_buffer)) { pr_warn("%s: Truncated dsprintf message %s\n", __func__, fmt); size = sizeof(tmp_buffer); } else { - size = len + 1; + size = (size_t)(len + 1); } buffer = kutf_mempool_alloc(pool, size); |