Hi Yong-Xuan, On Wed, Oct 1, 2025 at 6:15 AM Yong-Xuan Wang <yongxuan.w...@sifive.com> wrote: > > Add a test case that does some basic verification of the Vector ptrace > interface. This forks a child process then using ptrace to inspect and > manipulate the v31 register of the child. > > Signed-off-by: Yong-Xuan Wang <yongxuan.w...@sifive.com> > --- > tools/testing/selftests/riscv/vector/Makefile | 5 +- > .../selftests/riscv/vector/vstate_ptrace.c | 132 ++++++++++++++++++ > 2 files changed, 136 insertions(+), 1 deletion(-) > create mode 100644 tools/testing/selftests/riscv/vector/vstate_ptrace.c > > diff --git a/tools/testing/selftests/riscv/vector/Makefile > b/tools/testing/selftests/riscv/vector/Makefile > index 6f7497f4e7b3..45f25e9dd264 100644 > --- a/tools/testing/selftests/riscv/vector/Makefile > +++ b/tools/testing/selftests/riscv/vector/Makefile > @@ -2,7 +2,7 @@ > # Copyright (C) 2021 ARM Limited > # Originally tools/testing/arm64/abi/Makefile > > -TEST_GEN_PROGS := v_initval vstate_prctl > +TEST_GEN_PROGS := v_initval vstate_prctl vsate_ptrace > TEST_GEN_PROGS_EXTENDED := vstate_exec_nolibc v_exec_initval_nolibc > > include ../../lib.mk > @@ -26,3 +26,6 @@ $(OUTPUT)/v_initval: v_initval.c $(OUTPUT)/sys_hwprobe.o > $(OUTPUT)/v_helpers.o > $(OUTPUT)/v_exec_initval_nolibc: v_exec_initval_nolibc.c > $(CC) -nostdlib -static -include ../../../../include/nolibc/nolibc.h \ > -Wall $(CFLAGS) $(LDFLAGS) $^ -o $@ -lgcc > + > +$(OUTPUT)/vstate_ptrace: vstate_ptrace.c $(OUTPUT)/sys_hwprobe.o > $(OUTPUT)/v_helpers.o > + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ > diff --git a/tools/testing/selftests/riscv/vector/vstate_ptrace.c > b/tools/testing/selftests/riscv/vector/vstate_ptrace.c > new file mode 100644 > index 000000000000..8a7bcf318e59 > --- /dev/null > +++ b/tools/testing/selftests/riscv/vector/vstate_ptrace.c > @@ -0,0 +1,132 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +#include <stdio.h> > +#include <stdlib.h> > +#include <asm/ptrace.h> > +#include <linux/elf.h> > +#include <sys/ptrace.h> > +#include <sys/uio.h> > +#include <sys/wait.h> > +#include "../../kselftest.h" > +#include "v_helpers.h" > + > +int parent_set_val, child_set_val; > + > +static long do_ptrace(enum __ptrace_request op, pid_t pid, long type, size_t > size, void *data) > +{ > + struct iovec v_iovec = { > + .iov_len = size, > + .iov_base = data > + }; > + > + return ptrace(op, pid, type, &v_iovec); > +} > + > +static int do_child(void) > +{ > + int out; > + > + if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) { > + ksft_perror("PTRACE_TRACEME failed\n"); > + return EXIT_FAILURE; > + } > + > + asm volatile (".option push\n\t" > + ".option arch, +v\n\t" > + "vsetivli x0, 1, e32, m1, ta, ma\n\t" > + "vmv.s.x v31, %[in]\n\t" > + "ebreak\n\t" > + "vmv.x.s %[out], v31\n\t" > + ".option pop\n\t" > + : [out] "=r" (out) > + : [in] "r" (child_set_val)); > + > + if (out != parent_set_val) > + return EXIT_FAILURE; > + > + return EXIT_SUCCESS; > +} > + > +static void do_parent(pid_t child) > +{ > + int status; > + void *data = NULL; > + > + /* Attach to the child */ > + while (waitpid(child, &status, 0)) { > + if (WIFEXITED(status)) { > + ksft_test_result(WEXITSTATUS(status) == 0, "SETREGSET > vector\n"); > + goto out; > + } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == > SIGTRAP)) { > + size_t size, t; > + void *data, *v31; > + struct __riscv_v_regset_state *v_regset_hdr; > + struct user_regs_struct *gpreg; > + > + size = sizeof(*v_regset_hdr); > + data = malloc(size); > + if (!data) > + goto out; > + v_regset_hdr = (struct __riscv_v_regset_state *)data; > + > + if (do_ptrace(PTRACE_GETREGSET, child, > NT_RISCV_VECTOR, size, data)) > + goto out; > + > + ksft_print_msg("vlenb %ld\n", v_regset_hdr->vlenb); > + data = realloc(data, size + v_regset_hdr->vlenb * 32); > + if (!data) > + goto out; > + v31 = (void *)(data + size + v_regset_hdr->vlenb * > 31); > + size += v_regset_hdr->vlenb * 32; > + > + if (do_ptrace(PTRACE_GETREGSET, child, > NT_RISCV_VECTOR, size, data)) > + goto out; > + > + ksft_test_result(*(int *)v31 == child_set_val, > "GETREGSET vector\n"); > + > + *(int *)v31 = parent_set_val; > + if (do_ptrace(PTRACE_SETREGSET, child, > NT_RISCV_VECTOR, size, data)) > + goto out; > + > + /* move the pc forward */ > + size = sizeof(*gpreg); > + data = realloc(data, size); > + gpreg = (struct user_regs_struct *)data; > + > + if (do_ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, > size, data)) > + goto out; > + > + gpreg->pc += 2;
Just nitpicking here, simply adding 2 may fail if the program is not compiled with C. You may either +=4 and use ".option norvc" in the asm or determine the size of ebreak by decoding it. with or without the fix, Reviewed-by: Andy Chiu <andyb...@gmail.com>