Add testcase for recursive exception handling

This commit is contained in:
Hui, Chunyang 2023-09-18 11:39:57 +00:00 committed by volcano
parent 6da887d069
commit 6bf849634d

@ -212,19 +212,9 @@ static int killed_child() {
// ============================================================================
// Test catching and handling hardware exception
// ============================================================================
static int SIGFPE_RESURSIVE_LEVEL = 0;
static void handle_sigfpe(int num, siginfo_t *info, void *_context) {
printf("SIGFPE Caught\n");
assert(num == SIGFPE);
assert(info->si_signo == SIGFPE);
ucontext_t *ucontext = _context;
mcontext_t *mcontext = &ucontext->uc_mcontext;
// The faulty instruction should be `idiv %esi` (f7 fe)
mcontext->gregs[REG_RIP] += 2;
return;
}
#define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr)))
// Note: this function is fragile in the sense that compiler may not always
// emit the instruction pattern that triggers divide-by-zero as we expect.
@ -233,15 +223,68 @@ int div_maybe_zero(int x, int y) {
return x / y;
}
#define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr)))
static void handle_sigfpe(int num, siginfo_t *info, void *_context) {
printf("SIGFPE Caught\n");
assert(num == SIGFPE);
assert(info->si_signo == SIGFPE);
char x[512] __attribute__((aligned(16))) = {};
char y[512] __attribute__((aligned(16))) = {};
SIGFPE_RESURSIVE_LEVEL ++;
ucontext_t *ucontext = _context;
mcontext_t *mcontext = &ucontext->uc_mcontext;
// The faulty instruction should be `idiv %esi` (f7 fe)
mcontext->gregs[REG_RIP] += 2;
fxsave(x);
// Try modify the floating point register
float a = 3.00001234567890123 / 2.001;
printf("a = %f\n", a);
float value = 3.14f;
__asm__ volatile (
"movss %[newval], %%xmm0" // Move new value to xmm0 register
:
: [newval] "m" (value) // Input constraint: value is a memory operand
: "%xmm0" // Use xmm0 register
);
fxsave(y);
// Make sure the floating point registers are modified
if (memcmp(x, y, 512) == 0) {
printf("floating point registers is not modified\n");
abort();
}
// Recursively trigger exception
if (SIGFPE_RESURSIVE_LEVEL < 4) {
volatile int c;
// Trigger divide-by-zero exception
int a = 1;
int b = 0;
c = div_maybe_zero(a, b);
}
return;
}
int test_handle_sigfpe() {
static char stack[SIGSTKSZ * 4];
stack_t expected_ss = {
.ss_size = SIGSTKSZ * 4,
.ss_sp = stack,
.ss_flags = 0,
};
if (sigaltstack(&expected_ss, NULL) < 0) {
THROW_ERROR("failed to call sigaltstack");
}
// Set up a signal handler that handles divide-by-zero exception
struct sigaction new_action, old_action;
memset(&new_action, 0, sizeof(struct sigaction));
memset(&old_action, 0, sizeof(struct sigaction));
new_action.sa_sigaction = handle_sigfpe;
new_action.sa_flags = SA_SIGINFO;
new_action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
if (sigaction(SIGFPE, &new_action, &old_action) < 0) {
THROW_ERROR("registering new signal handler failed");
}
@ -273,7 +316,6 @@ int test_handle_sigfpe() {
return 0;
}
// TODO: rewrite this in assembly
int read_maybe_null(int *p) {
return *p;