checkasm/riscv: report an error upon SIGILL

Terminating the whole checkasm process is not very helpful. This will
report if an illegal instruction occurs while executing a tested
function. This is a common occurrence whilst developping RISC-V
assembler, due to the compatibility between vector configuration and
instruction done at run-time.
This commit is contained in:
Rémi Denis-Courmont 2023-07-12 22:48:53 +03:00
parent 286d674221
commit 7212466e73
3 changed files with 30 additions and 2 deletions

View File

@ -27,6 +27,7 @@
# define _GNU_SOURCE // for syscall (performance monitoring API), strsignal() # define _GNU_SOURCE // for syscall (performance monitoring API), strsignal()
#endif #endif
#include <signal.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -734,6 +735,14 @@ int main(int argc, char *argv[])
if (have_vfp(av_get_cpu_flags()) || have_neon(av_get_cpu_flags())) if (have_vfp(av_get_cpu_flags()) || have_neon(av_get_cpu_flags()))
checkasm_checked_call = checkasm_checked_call_vfp; checkasm_checked_call = checkasm_checked_call_vfp;
#endif #endif
#if ARCH_RISCV
struct sigaction act = {
.sa_handler = checkasm_handle_signal,
.sa_flags = 0,
};
sigaction(SIGILL, &act, NULL);
#endif
if (!tests[0].func || !cpus[0].flag) { if (!tests[0].func || !cpus[0].flag) {
fprintf(stderr, "checkasm: no tests to perform\n"); fprintf(stderr, "checkasm: no tests to perform\n");

View File

@ -23,6 +23,7 @@
#ifndef TESTS_CHECKASM_CHECKASM_H #ifndef TESTS_CHECKASM_CHECKASM_H
#define TESTS_CHECKASM_CHECKASM_H #define TESTS_CHECKASM_CHECKASM_H
#include <setjmp.h>
#include <stdint.h> #include <stdint.h>
#include "config.h" #include "config.h"
@ -211,14 +212,20 @@ void checkasm_checked_call(void *func, ...);
checked_call(func_new, 0, 0, 0, 0, 0, 0, 0, __VA_ARGS__,\ checked_call(func_new, 0, 0, 0, 0, 0, 0, 0, __VA_ARGS__,\
7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0)) 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0))
#elif ARCH_RISCV #elif ARCH_RISCV
void checkasm_set_function(void *); void checkasm_set_function(void *, sigjmp_buf);
void *checkasm_get_wrapper(void); void *checkasm_get_wrapper(void);
void checkasm_handle_signal(int signum);
#if (__riscv_xlen == 64) && defined (__riscv_d) #if (__riscv_xlen == 64) && defined (__riscv_d)
#define declare_new(ret, ...) \ #define declare_new(ret, ...) \
int checked_call_signum = 0; \
sigjmp_buf checked_call_jb; \
ret (*checked_call)(__VA_ARGS__) = checkasm_get_wrapper(); ret (*checked_call)(__VA_ARGS__) = checkasm_get_wrapper();
#define call_new(...) \ #define call_new(...) \
(checkasm_set_function(func_new), checked_call(__VA_ARGS__)) (checkasm_set_function(func_new, checked_call_jb), \
(checked_call_signum = sigsetjmp(checked_call_jb, 1)) == 0 \
? checked_call(__VA_ARGS__) \
: (checkasm_fail_signal(checked_call_signum), 0))
#endif #endif
#else #else
#define declare_new(ret, ...) #define declare_new(ret, ...)

View File

@ -41,6 +41,7 @@ endconst
checked_func: checked_func:
.quad 0 .quad 0
.quad 0
saved_regs: saved_regs:
/* Space to spill RA, SP, GP, TP, S0-S11 and FS0-FS11 */ /* Space to spill RA, SP, GP, TP, S0-S11 and FS0-FS11 */
@ -52,6 +53,7 @@ func checkasm_set_function
la.tls.ie t0, checked_func la.tls.ie t0, checked_func
add t0, tp, t0 add t0, tp, t0
sd a0, (t0) sd a0, (t0)
sd a1, 8(t0)
ret ret
endfunc endfunc
@ -175,4 +177,14 @@ func checkasm_get_wrapper, v
call checkasm_fail_func call checkasm_fail_func
j 4b j 4b
endfunc endfunc
func checkasm_handle_signal
mv a1, a0
la.tls.ie a0, checked_func
add a0, tp, a0
ld a0, 8(a0)
beqz a0, 8f
tail siglongjmp
8: tail abort /* No jump buffer to go to */
endfunc
#endif #endif