selftests/bpf: Add uprobe context registers changes test

Adding test to check we can change common register values through
uprobe program.

It's x86_64 specific test.

Acked-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/r/20250916215301.664963-4-jolsa@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Jiri Olsa 2025-09-16 23:52:58 +02:00 committed by Alexei Starovoitov
parent 4363264111
commit 7f8a05c5d3
2 changed files with 137 additions and 1 deletions

View File

@ -2,6 +2,7 @@
/* Copyright (c) 2023 Hengqi Chen */
#include <test_progs.h>
#include <asm/ptrace.h>
#include "test_uprobe.skel.h"
static FILE *urand_spawn(int *pid)
@ -33,7 +34,7 @@ static int urand_trigger(FILE **urand_pipe)
return exit_code;
}
void test_uprobe(void)
static void test_uprobe_attach(void)
{
LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
struct test_uprobe *skel;
@ -93,3 +94,114 @@ void test_uprobe(void)
pclose(urand_pipe);
test_uprobe__destroy(skel);
}
#ifdef __x86_64__
__naked __maybe_unused unsigned long uprobe_regs_change_trigger(void)
{
asm volatile (
"ret\n"
);
}
static __naked void uprobe_regs_change(struct pt_regs *before, struct pt_regs *after)
{
asm volatile (
"movq %r11, 48(%rdi)\n"
"movq %r10, 56(%rdi)\n"
"movq %r9, 64(%rdi)\n"
"movq %r8, 72(%rdi)\n"
"movq %rax, 80(%rdi)\n"
"movq %rcx, 88(%rdi)\n"
"movq %rdx, 96(%rdi)\n"
"movq %rsi, 104(%rdi)\n"
"movq %rdi, 112(%rdi)\n"
/* save 2nd argument */
"pushq %rsi\n"
"call uprobe_regs_change_trigger\n"
/* save return value and load 2nd argument pointer to rax */
"pushq %rax\n"
"movq 8(%rsp), %rax\n"
"movq %r11, 48(%rax)\n"
"movq %r10, 56(%rax)\n"
"movq %r9, 64(%rax)\n"
"movq %r8, 72(%rax)\n"
"movq %rcx, 88(%rax)\n"
"movq %rdx, 96(%rax)\n"
"movq %rsi, 104(%rax)\n"
"movq %rdi, 112(%rax)\n"
/* restore return value and 2nd argument */
"pop %rax\n"
"pop %rsi\n"
"movq %rax, 80(%rsi)\n"
"ret\n"
);
}
static void regs_common(void)
{
struct pt_regs before = {}, after = {}, expected = {
.rax = 0xc0ffe,
.rcx = 0xbad,
.rdx = 0xdead,
.r8 = 0x8,
.r9 = 0x9,
.r10 = 0x10,
.r11 = 0x11,
.rdi = 0x12,
.rsi = 0x13,
};
LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
struct test_uprobe *skel;
skel = test_uprobe__open_and_load();
if (!ASSERT_OK_PTR(skel, "skel_open"))
return;
skel->bss->my_pid = getpid();
skel->bss->regs = expected;
uprobe_opts.func_name = "uprobe_regs_change_trigger";
skel->links.test_regs_change = bpf_program__attach_uprobe_opts(skel->progs.test_regs_change,
-1,
"/proc/self/exe",
0 /* offset */,
&uprobe_opts);
if (!ASSERT_OK_PTR(skel->links.test_regs_change, "bpf_program__attach_uprobe_opts"))
goto cleanup;
uprobe_regs_change(&before, &after);
ASSERT_EQ(after.rax, expected.rax, "ax");
ASSERT_EQ(after.rcx, expected.rcx, "cx");
ASSERT_EQ(after.rdx, expected.rdx, "dx");
ASSERT_EQ(after.r8, expected.r8, "r8");
ASSERT_EQ(after.r9, expected.r9, "r9");
ASSERT_EQ(after.r10, expected.r10, "r10");
ASSERT_EQ(after.r11, expected.r11, "r11");
ASSERT_EQ(after.rdi, expected.rdi, "rdi");
ASSERT_EQ(after.rsi, expected.rsi, "rsi");
cleanup:
test_uprobe__destroy(skel);
}
static void test_uprobe_regs_change(void)
{
if (test__start_subtest("regs_change_common"))
regs_common();
}
#else
static void test_uprobe_regs_change(void) { }
#endif
void test_uprobe(void)
{
if (test__start_subtest("attach"))
test_uprobe_attach();
test_uprobe_regs_change();
}

View File

@ -59,3 +59,27 @@ int BPF_UPROBE(test4)
test4_result = 1;
return 0;
}
#if defined(__TARGET_ARCH_x86)
struct pt_regs regs;
SEC("uprobe")
int BPF_UPROBE(test_regs_change)
{
pid_t pid = bpf_get_current_pid_tgid() >> 32;
if (pid != my_pid)
return 0;
ctx->ax = regs.ax;
ctx->cx = regs.cx;
ctx->dx = regs.dx;
ctx->r8 = regs.r8;
ctx->r9 = regs.r9;
ctx->r10 = regs.r10;
ctx->r11 = regs.r11;
ctx->di = regs.di;
ctx->si = regs.si;
return 0;
}
#endif