Changing uretprobe_regs_trigger to allow the test for both
uprobe and uretprobe and renaming it to uprobe_regs_equal.
We check that both uprobe and uretprobe probes (bpf programs)
see expected registers with few exceptions.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
.../selftests/bpf/prog_tests/uprobe_syscall.c | 58 ++++++++++++++-----
.../selftests/bpf/progs/uprobe_syscall.c | 4 +-
2 files changed, 45 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
index f001986981ab..6d88c5b0f6aa 100644
--- a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
+++ b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
@@ -18,15 +18,17 @@
#pragma GCC diagnostic ignored "-Wattributes"
-__naked unsigned long uretprobe_regs_trigger(void)
+__attribute__((aligned(16)))
+__nocf_check __weak __naked unsigned long uprobe_regs_trigger(void)
{
asm volatile (
- "movq $0xdeadbeef, %rax\n"
+ ".byte 0x0f, 0x1f, 0x44, 0x00, 0x00 \n"
+ "movq $0xdeadbeef, %rax \n"
"ret\n"
);
}
-__naked void uretprobe_regs(struct pt_regs *before, struct pt_regs *after)
+__naked void uprobe_regs(struct pt_regs *before, struct pt_regs *after)
{
asm volatile (
"movq %r15, 0(%rdi)\n"
@@ -47,15 +49,17 @@ __naked void uretprobe_regs(struct pt_regs *before, struct pt_regs *after)
"movq $0, 120(%rdi)\n" /* orig_rax */
"movq $0, 128(%rdi)\n" /* rip */
"movq $0, 136(%rdi)\n" /* cs */
+ "pushq %rax\n"
"pushf\n"
"pop %rax\n"
"movq %rax, 144(%rdi)\n" /* eflags */
+ "pop %rax\n"
"movq %rsp, 152(%rdi)\n" /* rsp */
"movq $0, 160(%rdi)\n" /* ss */
/* save 2nd argument */
"pushq %rsi\n"
- "call uretprobe_regs_trigger\n"
+ "call uprobe_regs_trigger\n"
/* save return value and load 2nd argument pointer to rax */
"pushq %rax\n"
@@ -95,25 +99,37 @@ __naked void uretprobe_regs(struct pt_regs *before, struct pt_regs *after)
);
}
-static void test_uretprobe_regs_equal(void)
+static void test_uprobe_regs_equal(bool retprobe)
{
+ LIBBPF_OPTS(bpf_uprobe_opts, opts,
+ .retprobe = retprobe,
+ );
struct uprobe_syscall *skel = NULL;
struct pt_regs before = {}, after = {};
unsigned long *pb = (unsigned long *) &before;
unsigned long *pa = (unsigned long *) &after;
unsigned long *pp;
+ unsigned long offset;
unsigned int i, cnt;
- int err;
+
+ offset = get_uprobe_offset(&uprobe_regs_trigger);
+ if (!ASSERT_GE(offset, 0, "get_uprobe_offset"))
+ return;
skel = uprobe_syscall__open_and_load();
if (!ASSERT_OK_PTR(skel, "uprobe_syscall__open_and_load"))
goto cleanup;
- err = uprobe_syscall__attach(skel);
- if (!ASSERT_OK(err, "uprobe_syscall__attach"))
+ skel->links.probe = bpf_program__attach_uprobe_opts(skel->progs.probe,
+ 0, "/proc/self/exe", offset, &opts);
+ if (!ASSERT_OK_PTR(skel->links.probe, "bpf_program__attach_uprobe_opts"))
goto cleanup;
- uretprobe_regs(&before, &after);
+ /* make sure uprobe gets optimized */
+ if (!retprobe)
+ uprobe_regs_trigger();
+
+ uprobe_regs(&before, &after);
pp = (unsigned long *) &skel->bss->regs;
cnt = sizeof(before)/sizeof(*pb);
@@ -122,7 +138,7 @@ static void test_uretprobe_regs_equal(void)
unsigned int offset = i * sizeof(unsigned long);
/*
- * Check register before and after uretprobe_regs_trigger call
+ * Check register before and after uprobe_regs_trigger call
* that triggers the uretprobe.
*/
switch (offset) {
@@ -136,7 +152,7 @@ static void test_uretprobe_regs_equal(void)
/*
* Check register seen from bpf program and register after
- * uretprobe_regs_trigger call
+ * uprobe_regs_trigger call (with rax exception, check below).
*/
switch (offset) {
/*
@@ -149,6 +165,15 @@ static void test_uretprobe_regs_equal(void)
case offsetof(struct pt_regs, rsp):
case offsetof(struct pt_regs, ss):
break;
+ /*
+ * uprobe does not see return value in rax, it needs to see the
+ * original (before) rax value
+ */
+ case offsetof(struct pt_regs, rax):
+ if (!retprobe) {
+ ASSERT_EQ(pp[i], pb[i], "uprobe rax prog-before value check");
+ break;
+ }
default:
if (!ASSERT_EQ(pp[i], pa[i], "register prog-after value check"))
fprintf(stdout, "failed register offset %u\n", offset);
@@ -186,13 +211,13 @@ static void test_uretprobe_regs_change(void)
unsigned long cnt = sizeof(before)/sizeof(*pb);
unsigned int i, err, offset;
- offset = get_uprobe_offset(uretprobe_regs_trigger);
+ offset = get_uprobe_offset(uprobe_regs_trigger);
err = write_bpf_testmod_uprobe(offset);
if (!ASSERT_OK(err, "register_uprobe"))
return;
- uretprobe_regs(&before, &after);
+ uprobe_regs(&before, &after);
err = write_bpf_testmod_uprobe(0);
if (!ASSERT_OK(err, "unregister_uprobe"))
@@ -605,7 +630,8 @@ static void test_uretprobe_shadow_stack(void)
/* Run all the tests with shadow stack in place. */
shstk_is_enabled = true;
- test_uretprobe_regs_equal();
+ test_uprobe_regs_equal(false);
+ test_uprobe_regs_equal(true);
test_uretprobe_regs_change();
test_uretprobe_syscall_call();
@@ -728,7 +754,7 @@ static void test_uprobe_sigill(void)
static void __test_uprobe_syscall(void)
{
if (test__start_subtest("uretprobe_regs_equal"))
- test_uretprobe_regs_equal();
+ test_uprobe_regs_equal(true);
if (test__start_subtest("uretprobe_regs_change"))
test_uretprobe_regs_change();
if (test__start_subtest("uretprobe_syscall_call"))
@@ -747,6 +773,8 @@ static void __test_uprobe_syscall(void)
test_uprobe_race();
if (test__start_subtest("uprobe_sigill"))
test_uprobe_sigill();
+ if (test__start_subtest("uprobe_regs_equal"))
+ test_uprobe_regs_equal(false);
}
#else
static void __test_uprobe_syscall(void)
diff --git a/tools/testing/selftests/bpf/progs/uprobe_syscall.c b/tools/testing/selftests/bpf/progs/uprobe_syscall.c
index 8a4fa6c7ef59..e08c31669e5a 100644
--- a/tools/testing/selftests/bpf/progs/uprobe_syscall.c
+++ b/tools/testing/selftests/bpf/progs/uprobe_syscall.c
@@ -7,8 +7,8 @@ struct pt_regs regs;
char _license[] SEC("license") = "GPL";
-SEC("uretprobe//proc/self/exe:uretprobe_regs_trigger")
-int uretprobe(struct pt_regs *ctx)
+SEC("uprobe")
+int probe(struct pt_regs *ctx)
{
__builtin_memcpy(®s, ctx, sizeof(regs));
return 0;
--
2.49.0
On Mon, Apr 21, 2025 at 2:48 PM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Changing uretprobe_regs_trigger to allow the test for both
> uprobe and uretprobe and renaming it to uprobe_regs_equal.
>
> We check that both uprobe and uretprobe probes (bpf programs)
> see expected registers with few exceptions.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
> .../selftests/bpf/prog_tests/uprobe_syscall.c | 58 ++++++++++++++-----
> .../selftests/bpf/progs/uprobe_syscall.c | 4 +-
> 2 files changed, 45 insertions(+), 17 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
> index f001986981ab..6d88c5b0f6aa 100644
> --- a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
> +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
> @@ -18,15 +18,17 @@
>
> #pragma GCC diagnostic ignored "-Wattributes"
>
> -__naked unsigned long uretprobe_regs_trigger(void)
> +__attribute__((aligned(16)))
> +__nocf_check __weak __naked unsigned long uprobe_regs_trigger(void)
> {
> asm volatile (
> - "movq $0xdeadbeef, %rax\n"
> + ".byte 0x0f, 0x1f, 0x44, 0x00, 0x00 \n"
Is it me not being hardcore enough... But is anyone supposed to know
that this is nop5? ;) maybe add /* nop5 */ comment on the side?
> + "movq $0xdeadbeef, %rax \n"
ret\n doesn't align newline, and uprobe_regs below don't either. So
maybe don't align them at all here?
> "ret\n"
> );
> }
>
> -__naked void uretprobe_regs(struct pt_regs *before, struct pt_regs *after)
> +__naked void uprobe_regs(struct pt_regs *before, struct pt_regs *after)
> {
> asm volatile (
> "movq %r15, 0(%rdi)\n"
> @@ -47,15 +49,17 @@ __naked void uretprobe_regs(struct pt_regs *before, struct pt_regs *after)
> "movq $0, 120(%rdi)\n" /* orig_rax */
> "movq $0, 128(%rdi)\n" /* rip */
> "movq $0, 136(%rdi)\n" /* cs */
> + "pushq %rax\n"
> "pushf\n"
> "pop %rax\n"
> "movq %rax, 144(%rdi)\n" /* eflags */
> + "pop %rax\n"
> "movq %rsp, 152(%rdi)\n" /* rsp */
> "movq $0, 160(%rdi)\n" /* ss */
>
> /* save 2nd argument */
> "pushq %rsi\n"
> - "call uretprobe_regs_trigger\n"
> + "call uprobe_regs_trigger\n"
>
> /* save return value and load 2nd argument pointer to rax */
> "pushq %rax\n"
> @@ -95,25 +99,37 @@ __naked void uretprobe_regs(struct pt_regs *before, struct pt_regs *after)
> );
> }
>
> -static void test_uretprobe_regs_equal(void)
> +static void test_uprobe_regs_equal(bool retprobe)
> {
> + LIBBPF_OPTS(bpf_uprobe_opts, opts,
> + .retprobe = retprobe,
> + );
> struct uprobe_syscall *skel = NULL;
> struct pt_regs before = {}, after = {};
> unsigned long *pb = (unsigned long *) &before;
> unsigned long *pa = (unsigned long *) &after;
> unsigned long *pp;
> + unsigned long offset;
> unsigned int i, cnt;
> - int err;
> +
> + offset = get_uprobe_offset(&uprobe_regs_trigger);
> + if (!ASSERT_GE(offset, 0, "get_uprobe_offset"))
> + return;
>
> skel = uprobe_syscall__open_and_load();
> if (!ASSERT_OK_PTR(skel, "uprobe_syscall__open_and_load"))
> goto cleanup;
>
> - err = uprobe_syscall__attach(skel);
> - if (!ASSERT_OK(err, "uprobe_syscall__attach"))
> + skel->links.probe = bpf_program__attach_uprobe_opts(skel->progs.probe,
> + 0, "/proc/self/exe", offset, &opts);
> + if (!ASSERT_OK_PTR(skel->links.probe, "bpf_program__attach_uprobe_opts"))
> goto cleanup;
>
> - uretprobe_regs(&before, &after);
> + /* make sure uprobe gets optimized */
> + if (!retprobe)
> + uprobe_regs_trigger();
> +
> + uprobe_regs(&before, &after);
>
> pp = (unsigned long *) &skel->bss->regs;
> cnt = sizeof(before)/sizeof(*pb);
> @@ -122,7 +138,7 @@ static void test_uretprobe_regs_equal(void)
> unsigned int offset = i * sizeof(unsigned long);
>
> /*
> - * Check register before and after uretprobe_regs_trigger call
> + * Check register before and after uprobe_regs_trigger call
> * that triggers the uretprobe.
> */
> switch (offset) {
> @@ -136,7 +152,7 @@ static void test_uretprobe_regs_equal(void)
>
> /*
> * Check register seen from bpf program and register after
> - * uretprobe_regs_trigger call
> + * uprobe_regs_trigger call (with rax exception, check below).
> */
> switch (offset) {
> /*
> @@ -149,6 +165,15 @@ static void test_uretprobe_regs_equal(void)
> case offsetof(struct pt_regs, rsp):
> case offsetof(struct pt_regs, ss):
> break;
> + /*
> + * uprobe does not see return value in rax, it needs to see the
> + * original (before) rax value
> + */
> + case offsetof(struct pt_regs, rax):
> + if (!retprobe) {
> + ASSERT_EQ(pp[i], pb[i], "uprobe rax prog-before value check");
> + break;
> + }
> default:
> if (!ASSERT_EQ(pp[i], pa[i], "register prog-after value check"))
> fprintf(stdout, "failed register offset %u\n", offset);
> @@ -186,13 +211,13 @@ static void test_uretprobe_regs_change(void)
> unsigned long cnt = sizeof(before)/sizeof(*pb);
> unsigned int i, err, offset;
>
> - offset = get_uprobe_offset(uretprobe_regs_trigger);
> + offset = get_uprobe_offset(uprobe_regs_trigger);
>
> err = write_bpf_testmod_uprobe(offset);
> if (!ASSERT_OK(err, "register_uprobe"))
> return;
>
> - uretprobe_regs(&before, &after);
> + uprobe_regs(&before, &after);
>
> err = write_bpf_testmod_uprobe(0);
> if (!ASSERT_OK(err, "unregister_uprobe"))
> @@ -605,7 +630,8 @@ static void test_uretprobe_shadow_stack(void)
> /* Run all the tests with shadow stack in place. */
> shstk_is_enabled = true;
>
> - test_uretprobe_regs_equal();
> + test_uprobe_regs_equal(false);
> + test_uprobe_regs_equal(true);
> test_uretprobe_regs_change();
> test_uretprobe_syscall_call();
>
> @@ -728,7 +754,7 @@ static void test_uprobe_sigill(void)
> static void __test_uprobe_syscall(void)
> {
> if (test__start_subtest("uretprobe_regs_equal"))
> - test_uretprobe_regs_equal();
> + test_uprobe_regs_equal(true);
> if (test__start_subtest("uretprobe_regs_change"))
> test_uretprobe_regs_change();
> if (test__start_subtest("uretprobe_syscall_call"))
> @@ -747,6 +773,8 @@ static void __test_uprobe_syscall(void)
> test_uprobe_race();
> if (test__start_subtest("uprobe_sigill"))
> test_uprobe_sigill();
> + if (test__start_subtest("uprobe_regs_equal"))
> + test_uprobe_regs_equal(false);
> }
> #else
> static void __test_uprobe_syscall(void)
> diff --git a/tools/testing/selftests/bpf/progs/uprobe_syscall.c b/tools/testing/selftests/bpf/progs/uprobe_syscall.c
> index 8a4fa6c7ef59..e08c31669e5a 100644
> --- a/tools/testing/selftests/bpf/progs/uprobe_syscall.c
> +++ b/tools/testing/selftests/bpf/progs/uprobe_syscall.c
> @@ -7,8 +7,8 @@ struct pt_regs regs;
>
> char _license[] SEC("license") = "GPL";
>
> -SEC("uretprobe//proc/self/exe:uretprobe_regs_trigger")
> -int uretprobe(struct pt_regs *ctx)
> +SEC("uprobe")
> +int probe(struct pt_regs *ctx)
> {
> __builtin_memcpy(®s, ctx, sizeof(regs));
> return 0;
> --
> 2.49.0
>
On Wed, Apr 23, 2025 at 10:46:24AM -0700, Andrii Nakryiko wrote:
> On Mon, Apr 21, 2025 at 2:48 PM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Changing uretprobe_regs_trigger to allow the test for both
> > uprobe and uretprobe and renaming it to uprobe_regs_equal.
> >
> > We check that both uprobe and uretprobe probes (bpf programs)
> > see expected registers with few exceptions.
> >
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> > .../selftests/bpf/prog_tests/uprobe_syscall.c | 58 ++++++++++++++-----
> > .../selftests/bpf/progs/uprobe_syscall.c | 4 +-
> > 2 files changed, 45 insertions(+), 17 deletions(-)
> >
> > diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
> > index f001986981ab..6d88c5b0f6aa 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
> > @@ -18,15 +18,17 @@
> >
> > #pragma GCC diagnostic ignored "-Wattributes"
> >
> > -__naked unsigned long uretprobe_regs_trigger(void)
> > +__attribute__((aligned(16)))
> > +__nocf_check __weak __naked unsigned long uprobe_regs_trigger(void)
> > {
> > asm volatile (
> > - "movq $0xdeadbeef, %rax\n"
> > + ".byte 0x0f, 0x1f, 0x44, 0x00, 0x00 \n"
>
> Is it me not being hardcore enough... But is anyone supposed to know
> that this is nop5? ;) maybe add /* nop5 */ comment on the side?
ok, will add the comment :)
>
> > + "movq $0xdeadbeef, %rax \n"
>
> ret\n doesn't align newline, and uprobe_regs below don't either. So
> maybe don't align them at all here?
ok
thanks,
jirka
© 2016 - 2025 Red Hat, Inc.