Add testcase for recursive exception handling
This commit is contained in:
parent
6da887d069
commit
6bf849634d
@ -212,19 +212,9 @@ static int killed_child() {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test catching and handling hardware exception
|
// Test catching and handling hardware exception
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
static int SIGFPE_RESURSIVE_LEVEL = 0;
|
||||||
|
|
||||||
static void handle_sigfpe(int num, siginfo_t *info, void *_context) {
|
#define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr)))
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: this function is fragile in the sense that compiler may not always
|
// 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.
|
// 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;
|
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() {
|
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
|
// Set up a signal handler that handles divide-by-zero exception
|
||||||
struct sigaction new_action, old_action;
|
struct sigaction new_action, old_action;
|
||||||
memset(&new_action, 0, sizeof(struct sigaction));
|
memset(&new_action, 0, sizeof(struct sigaction));
|
||||||
memset(&old_action, 0, sizeof(struct sigaction));
|
memset(&old_action, 0, sizeof(struct sigaction));
|
||||||
new_action.sa_sigaction = handle_sigfpe;
|
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) {
|
if (sigaction(SIGFPE, &new_action, &old_action) < 0) {
|
||||||
THROW_ERROR("registering new signal handler failed");
|
THROW_ERROR("registering new signal handler failed");
|
||||||
}
|
}
|
||||||
@ -273,7 +316,6 @@ int test_handle_sigfpe() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: rewrite this in assembly
|
// TODO: rewrite this in assembly
|
||||||
int read_maybe_null(int *p) {
|
int read_maybe_null(int *p) {
|
||||||
return *p;
|
return *p;
|
||||||
|
Loading…
Reference in New Issue
Block a user