The current kprobe_multi_bench_attach/kernel test reads sym names from /sys/kernel/tracing/available_filter_functions. Some names do not agree with the corresponding entries in /proc/kallsyms since the corresponding /proc/kallsyms syms have suffix '.llvm.<hash>'. Actually, if we pass symbol names in /proc/kallsyms, kprobe_multi_attach will be okay. This patch added a new subtest where addresses are retrieved from /sys/kernel/tracing/available_filter_functions_addrs, and use the address to consule /proc/kallsyms to get the function name. Signed-off-by: Yonghong Song <yonghong.song@xxxxxxxxx> --- .../bpf/prog_tests/kprobe_multi_test.c | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c index f6130f4f3d88..142309ced146 100644 --- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c +++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c @@ -438,6 +438,102 @@ static int get_syms(char ***symsp, size_t *cntp, bool kernel) return err; } +static int get_syms_from_addr(char ***symsp, size_t *cntp) +{ + char *name = NULL, **syms = NULL; + size_t cap = 0, cnt = 0, i; + struct hashmap *map; + struct ksym *ks; + char buf[256]; + FILE *f; + int err = 0; + void *addr; + + if (!ASSERT_OK(load_kallsyms(), "load_kallsyms")) + return -EINVAL; + /* + * The available_filter_functions contains many duplicates, + * but other than that all symbols are usable in kprobe multi + * interface. + * Filtering out duplicates by using hashmap__add, which won't + * add existing entry. + */ + + if (access("/sys/kernel/tracing/trace", F_OK) == 0) + f = fopen("/sys/kernel/tracing/available_filter_functions_addrs", "r"); + else + f = fopen("/sys/kernel/debug/tracing/available_filter_functions_addrs", "r"); + + if (!f) + return -ENOENT; + + map = hashmap__new(symbol_hash, symbol_equal, NULL); + if (IS_ERR(map)) { + err = libbpf_get_error(map); + goto error; + } + + while (fgets(buf, sizeof(buf), f)) { + if (strchr(buf, '[')) + continue; + + if (sscanf(buf, "%p$*[^\n]\n", &addr) != 1) + continue; + + ks = ksym_search((long)addr); + if (!ks) + return -EINVAL; + + name = ks->name; + + /* + * We attach to almost all kernel functions and some of them + * will cause 'suspicious RCU usage' when fprobe is attached + * to them. Filter out the current culprits - arch_cpu_idle + * default_idle and rcu_* functions. + */ + if (!strcmp(name, "arch_cpu_idle")) + continue; + if (!strcmp(name, "default_idle")) + continue; + if (!strncmp(name, "rcu_", 4)) + continue; + if (!strcmp(name, "bpf_dispatcher_xdp_func")) + continue; + if (!strncmp(name, "__ftrace_invalid_address__", + sizeof("__ftrace_invalid_address__") - 1)) + continue; + + err = hashmap__add(map, name, 0); + if (err == -EEXIST) { + err = 0; + continue; + } + if (err) + goto error; + + err = libbpf_ensure_mem((void **) &syms, &cap, + sizeof(*syms), cnt + 1); + if (err) + goto error; + + syms[cnt++] = name; + } + + *symsp = syms; + *cntp = cnt; + +error: + fclose(f); + hashmap__free(map); + if (err) { + for (i = 0; i < cnt; i++) + free(syms[i]); + free(syms); + } + return err; +} + static void test_kprobe_multi_bench_attach(bool kernel) { LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); @@ -521,6 +617,47 @@ static void test_attach_override(void) kprobe_multi_override__destroy(skel); } +static void test_attach_kernel_addrs_to_sym(void) +{ + LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); + struct kprobe_multi_empty *skel; + struct bpf_link *link; + char **syms = NULL; + size_t cnt = 0; + int i, err; + + err = get_syms_from_addr(&syms, &cnt); + if (err == -ENOENT) { + test__skip(); + return; + } + if (!ASSERT_OK(err, "get_syms_from_addr")) + return; + + skel = kprobe_multi_empty__open_and_load(); + if (!ASSERT_OK_PTR(skel, "kprobe_multi_empty__open_and_load")) + goto cleanup; + + opts.syms = (const char **) syms; + opts.cnt = cnt; + + link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe_empty, + NULL, &opts); + + if (!ASSERT_OK_PTR(link, "bpf_program__attach_kprobe_multi_opts")) + goto cleanup; + + bpf_link__destroy(link); + +cleanup: + kprobe_multi_empty__destroy(skel); + if (syms) { + for (i = 0; i < cnt; i++) + free(syms[i]); + free(syms); + } +} + void serial_test_kprobe_multi_bench_attach(void) { if (test__start_subtest("kernel")) @@ -550,4 +687,6 @@ void test_kprobe_multi_test(void) test_attach_api_fails(); if (test__start_subtest("attach_override")) test_attach_override(); + if (test__start_subtest("kernel_addrs_to_sym")) + test_attach_kernel_addrs_to_sym(); } -- 2.43.0