I have the following code attempting to run in xv6:
void handle_signal(siginfo_t info)
{
printf(1, "Caught signal %d...\n", info.signum);
if (info.signum == SIGFPE)
printf(1, "TEST PASSED\n");
else
printf(1, "TEST FAILED: wrong signal sent.\n");
return;
}
int main(int argc, char *argv[])
{
int x = 5;
int y = 0;
//int z = 0;
signal(SIGFPE, handle_signal);
x = x / y;
//x = x / z;
printf(1, "TEST FAILED: no signal sent.\n");
return 0;
}
The signal handler gets pushed onto the stack like this:
void handle_signal(int signo, struct trapframe *tf){
*((uint*)(tf->esp-4)) = tf->eip;
*((uint*)(tf->esp-8)) = proc->tf->eax;
*((uint*)(tf->esp-12)) = proc->tf->ecx;
*((uint*)(tf->esp-16)) = proc->tf->edx;
*((uint*)(tf->esp-20)) = signo;
*((uint*)(tf->esp-24)) =(uint)proc->pop;
tf->esp = tf->esp-24;
tf->eip = (uint)(proc->sigHandlers[signo]);
}
So I'm setting the bottom of the stack to the old instruction pointer, which in this case should be the instruction
x = x / y;
Then I'm pushing the volatile registers, pushing the signal handler argument on, pushing the function that will pop the registers, and then finally setting eip (the instruction pointer) equal to the address of the signal handler.
and here is my pop function:
void popregs(void){
__asm__ (
"add $8, %esp;"
"pop %edx;"
"pop %ecx;"
"pop %eax;"
"ret");
}
Ordinarily, this code should run and get stuck in an infinite loop of SIGFPE calls, as I'm setting the instruction pointer back to that x = x/y call every single time the handler gets run. However, for some reason, it skips ahead and finishes the program, and then segmentation faults with a wildly inaccurate EIP value.
What's really confusing me is that if I add another instruction, x = x/z, right underneath, it works perfectly. When I try to print out the EIP of the program, it's correctly pointing to x = x/y, so it isn't even executing the x/z part.
Could anybody help me understand this? I'm struggling to understand what might be happening in the stack