Add tests that verify operation of URDT probes for both the statically and dynamically-linked libbpf cases. Ensure probe attach and auto-attach succeed, and argument counts, cookies and argument values match expectations. Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx> --- tools/testing/selftests/bpf/Makefile | 2 +- tools/testing/selftests/bpf/prog_tests/urdt.c | 173 ++++++++++++++++++ tools/testing/selftests/bpf/progs/test_urdt.c | 100 ++++++++++ .../selftests/bpf/progs/test_urdt_shared.c | 59 ++++++ 4 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/urdt.c create mode 100644 tools/testing/selftests/bpf/progs/test_urdt.c create mode 100644 tools/testing/selftests/bpf/progs/test_urdt_shared.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index fd15017ed3b1..d21acb95a3e1 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -39,7 +39,7 @@ CFLAGS += -g $(OPT_FLAGS) -rdynamic \ -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \ -I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT) LDFLAGS += $(SAN_LDFLAGS) -LDLIBS += $(LIBELF_LIBS) -lz -lrt -lpthread +LDLIBS += $(LIBELF_LIBS) -lz -lrt -lpthread -ldl ifneq ($(LLVM),) # Silence some warnings when compiled with clang diff --git a/tools/testing/selftests/bpf/prog_tests/urdt.c b/tools/testing/selftests/bpf/prog_tests/urdt.c new file mode 100644 index 000000000000..725d064d78f2 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/urdt.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024, Oracle and/or its affiliates. */ + +#include <test_progs.h> + +#include <dlfcn.h> + +#include "../sdt.h" + +#include "test_urdt.skel.h" +#include "test_urdt_shared.skel.h" + +static volatile __u64 bla = 0xFEDCBA9876543210ULL; + +static void subtest_basic_urdt(void) +{ + LIBBPF_OPTS(bpf_urdt_opts, opts); + struct test_urdt *skel; + struct test_urdt__bss *bss; + long x = 1; + int y = 42; + int err; + int i; + + skel = test_urdt__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + + bss = skel->bss; + bss->my_pid = getpid(); + + err = test_urdt__attach(skel); + if (!ASSERT_OK(err, "skel_attach")) + goto cleanup; + + /* urdt0 won't be auto-attached */ + opts.urdt_cookie = 0xcafedead; + opts.urdt_nargs = 0; + skel->links.urdt0 = bpf_program__attach_urdt(skel->progs.urdt0, + 0 /*self*/, "/proc/self/exe", + "dyn", "urdt0", &opts); + if (!ASSERT_OK_PTR(skel->links.urdt0, "urdt0_link")) + goto cleanup; + + BPF_URDT_PROBE0("dyn", "urdt0"); + + ASSERT_EQ(bss->urdt0_called, 1, "urdt0_called"); + + ASSERT_EQ(bss->urdt0_cookie, 0xcafedead, "urdt0_cookie"); + ASSERT_EQ(bss->urdt0_arg_cnt, 0, "urdt0_arg_cnt"); + ASSERT_EQ(bss->urdt0_arg_ret, -ENOENT, "urdt0_arg_ret"); + + BPF_URDT_PROBE3("dyn", "urdt3", x, y, &bla); + + ASSERT_EQ(bss->urdt3_called, 1, "urdt3_called"); + /* ensure the other 3-arg URDT probe does not trigger */ + ASSERT_EQ(bss->urdt3alt_called, 0, "urdt3alt_notcalled"); + /* auto-attached urdt3 gets default zero cookie value */ + ASSERT_EQ(bss->urdt3_cookie, 0, "urdt3_cookie"); + ASSERT_EQ(bss->urdt3_arg_cnt, 3, "urdt3_arg_cnt"); + + ASSERT_EQ(bss->urdt3_arg1, 1, "urdt3_arg1"); + ASSERT_EQ(bss->urdt3_arg2, 42, "urdt3_arg2"); + ASSERT_EQ((long)bss->urdt3_arg3, (long)&bla, "urdt3_arg3"); + + /* now call alternative 3-arg function, and make sure dyn/urdt3 + * does not trigger. + */ + BPF_URDT_PROBE3("dyn", "urdt3alt", y, &bla, x); + + ASSERT_EQ(bss->urdt3alt_called, 1, "urdt3alt_called"); + ASSERT_EQ(bss->urdt3_called, 1, "urdt3_notcalled"); + + ASSERT_EQ(bss->urdt3alt_arg1, 42, "urdt3alt_arg1"); + ASSERT_EQ((long)bss->urdt3alt_arg2, (long)&bla, "urdt3_arg3"); + ASSERT_EQ(bss->urdt3alt_arg3, 1, "urdt3alt_arg3"); + + BPF_URDT_PROBE11("dyn", "urdt11", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + + ASSERT_EQ(bss->urdt11_called, 1, "urdt11_called"); + ASSERT_EQ(bss->urdt3_called, 1, "urdt3_called"); + for (i = 0; i < 11; i++) + ASSERT_EQ(bss->urdt11_args[i], i + 1, "urdt11_arg"); + +cleanup: + test_urdt__destroy(skel); +} + +#define LIBBPF_SO_PATH "./tools/build/libbpf/libbpf.so" + +/* verify shared object attach/firing works for libbpf.so */ +static void subtest_shared_urdt(void) +{ + LIBBPF_OPTS(bpf_urdt_opts, opts); + struct test_urdt_shared *skel; + void *dlh; + void (*probe0)(const char *provider, const char *probe); + void (*probe4)(const char *provider, const char *probe, long arg1, long arg2, + long arg3, long arg4); + struct test_urdt_shared__bss *bss; + long x = 1; + int y = 42; + int z = 3; + int err; + + skel = test_urdt_shared__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + bss = skel->bss; + bss->my_pid = getpid(); + + err = test_urdt_shared__attach(skel); + if (!ASSERT_OK(err, "skel_attach")) + goto cleanup; + + /* urdt0 won't be auto-attached */ + opts.urdt_cookie = 0xcafedead; + opts.urdt_nargs = 0; + skel->links.urdt0 = bpf_program__attach_urdt(skel->progs.urdt0, + -1 /* all */, + LIBBPF_SO_PATH, + "dyn", "urdt0", &opts); + if (!ASSERT_OK_PTR(skel->links.urdt0, "urdt0_link")) + goto cleanup; + + /* test_progs is statically linked with libbpf, so we need to dlopen/dlsym + * probe firing functions in the shared object we have attached to in order + * to trigger probe firing. If a program is dynamically linked to libbpf + * for probe firing, this won't be needed, but we want to make sure this + * mode of operation works as it will likely be the common case. + */ + dlh = dlopen(LIBBPF_SO_PATH, RTLD_NOW); + if (!ASSERT_NEQ(dlh, NULL, "dlopen")) + goto cleanup; + probe0 = dlsym(dlh, "bpf_urdt__probe0"); + if (!ASSERT_NEQ(probe0, NULL, "dlsym_probe0")) + goto cleanup; + probe4 = dlsym(dlh, "bpf_urdt__probe4"); + if (!ASSERT_NEQ(probe4, NULL, "dlsym_probe4")) + goto cleanup; + + probe0("dyn", "urdt0"); + + ASSERT_EQ(bss->urdt0_called, 1, "urdt0_called"); + + ASSERT_EQ(bss->urdt0_cookie, 0xcafedead, "urdt0_cookie"); + ASSERT_EQ(bss->urdt0_arg_cnt, 0, "urdt0_arg_cnt"); + ASSERT_EQ(bss->urdt0_arg_ret, -ENOENT, "urdt0_arg_ret"); + + probe4("dyn", "urdt4", (long)x, (long)y, (long)z, (long)&bla); + + ASSERT_EQ(bss->urdt4_called, 1, "urdt4_called"); + /* auto-attached urdt4 gets default zero cookie value */ + ASSERT_EQ(bss->urdt4_cookie, 0, "urdt4_cookie"); + ASSERT_EQ(bss->urdt4_arg_cnt, 4, "urdt4_arg_cnt"); + + ASSERT_EQ(bss->urdt4_arg1, 1, "urdt4_arg1"); + ASSERT_EQ(bss->urdt4_arg2, 42, "urdt4_arg2"); + ASSERT_EQ(bss->urdt4_arg3, 3, "urdt4_arg3"); + ASSERT_EQ((long)bss->urdt4_arg4, (long)&bla, "urdt4_arg4"); +cleanup: + if (dlh) + dlclose(dlh); + test_urdt_shared__destroy(skel); +} + +void test_urdt(void) +{ + if (test__start_subtest("basic")) + subtest_basic_urdt(); + if (test__start_subtest("shared")) + subtest_shared_urdt(); +} diff --git a/tools/testing/selftests/bpf/progs/test_urdt.c b/tools/testing/selftests/bpf/progs/test_urdt.c new file mode 100644 index 000000000000..82d5fbdc5744 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_urdt.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024, Oracle and/or its affiliates. */ + +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/urdt.bpf.h> + +int my_pid; + +int urdt0_called; +int urdt0_cookie; +int urdt0_arg_cnt; +int urdt0_arg_ret; + +SEC("urdt") +int BPF_URDT(urdt0) +{ + long tmp; + + if (my_pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + __sync_fetch_and_add(&urdt0_called, 1); + + urdt0_cookie = bpf_urdt_cookie(ctx); + urdt0_arg_cnt = bpf_urdt_arg_cnt(ctx); + /* should return -ENOENT for any arg_num */ + urdt0_arg_ret = bpf_usdt_arg(ctx, bpf_get_prandom_u32(), &tmp); + return 0; +} + +int urdt3_called; +int urdt3_cookie; +int urdt3_arg_cnt; +long urdt3_arg1; +int urdt3_arg2; +__u64 *urdt3_arg3; + +SEC("urdt//proc/self/exe:3:dyn:urdt3") +int BPF_URDT(urdt3, long x, int y, __u64 *bla) +{ + if (my_pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + __sync_fetch_and_add(&urdt3_called, 1); + + __sync_fetch_and_add(&urdt3_cookie, bpf_urdt_cookie(ctx)); + __sync_fetch_and_add(&urdt3_arg_cnt, bpf_urdt_arg_cnt(ctx)); + + __sync_fetch_and_add(&urdt3_arg1, x); + __sync_fetch_and_add(&urdt3_arg2, y); + __sync_fetch_and_add(&urdt3_arg3, bla); + + return 0; +} + +int urdt3alt_called; +int urdt3alt_cookie; +int urdt3alt_arg1; +__u64 *urdt3alt_arg2; +long urdt3alt_arg3; + +SEC("urdt//proc/self/exe:3:dyn:urdt3alt") +int BPF_URDT(urdt3alt, int y, __u64 *bla, long x) +{ + __sync_fetch_and_add(&urdt3alt_called, 1); + + __sync_fetch_and_add(&urdt3alt_cookie, bpf_urdt_cookie(ctx)); + + __sync_fetch_and_add(&urdt3alt_arg1, y); + __sync_fetch_and_add(&urdt3alt_arg2, bla); + __sync_fetch_and_add(&urdt3alt_arg3, x); + + return 0; +} + +int urdt11_called; +int urdt11_args[11]; + +SEC("urdt//proc/self/exe:11:dyn:urdt11") +int BPF_URDT(urdt11, int arg1, int arg2, int arg3, int arg4, int arg5, + int arg6, int arg7, int arg8, int arg9, int arg10, int arg11) +{ + __sync_fetch_and_add(&urdt11_called, 1); + __sync_fetch_and_add(&urdt11_args[0], arg1); + __sync_fetch_and_add(&urdt11_args[1], arg2); + __sync_fetch_and_add(&urdt11_args[2], arg3); + __sync_fetch_and_add(&urdt11_args[3], arg4); + __sync_fetch_and_add(&urdt11_args[4], arg5); + __sync_fetch_and_add(&urdt11_args[5], arg6); + __sync_fetch_and_add(&urdt11_args[6], arg7); + __sync_fetch_and_add(&urdt11_args[7], arg8); + __sync_fetch_and_add(&urdt11_args[8], arg9); + __sync_fetch_and_add(&urdt11_args[9], arg10); + __sync_fetch_and_add(&urdt11_args[10], arg11); + + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_urdt_shared.c b/tools/testing/selftests/bpf/progs/test_urdt_shared.c new file mode 100644 index 000000000000..2cdb181f73bd --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_urdt_shared.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024, Oracle and/or its affiliates. */ + +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/urdt.bpf.h> + +int my_pid; + +int urdt0_called; +int urdt0_cookie; +int urdt0_arg_cnt; +int urdt0_arg_ret; + +SEC("urdt") +int BPF_URDT(urdt0) +{ + long tmp; + + if (my_pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + __sync_fetch_and_add(&urdt0_called, 1); + + urdt0_cookie = bpf_urdt_cookie(ctx); + urdt0_arg_cnt = bpf_urdt_arg_cnt(ctx); + /* should return -ENOENT for any arg_num */ + urdt0_arg_ret = bpf_usdt_arg(ctx, bpf_get_prandom_u32(), &tmp); + return 0; +} + +int urdt4_called; +int urdt4_cookie; +int urdt4_arg_cnt; +long urdt4_arg1; +int urdt4_arg2; +int urdt4_arg3; +__u64 *urdt4_arg4; + +SEC("urdt/./tools/build/libbpf/libbpf.so:4:dyn:urdt4") +int BPF_URDT(urdt4, long x, int y, int z, __u64 *bla) +{ + if (my_pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + __sync_fetch_and_add(&urdt4_called, 1); + + __sync_fetch_and_add(&urdt4_cookie, bpf_urdt_cookie(ctx)); + __sync_fetch_and_add(&urdt4_arg_cnt, bpf_urdt_arg_cnt(ctx)); + + __sync_fetch_and_add(&urdt4_arg1, x); + __sync_fetch_and_add(&urdt4_arg2, y); + __sync_fetch_and_add(&urdt4_arg3, z); + __sync_fetch_and_add(&urdt4_arg4, bla); + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- 2.39.3