1

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

Mikey Chen
  • 2,370
  • 1
  • 19
  • 31
  • Haha everybody gets this assignment? :) Anyway, you are making assumptions about the compiler generated prologue in `popregs` which are probably wrong. Also you don't even comment where you got the `add $8, %esp` from. A better way would be to put the saved registers into the `struct siginfo_t` and make sure that gets passed to popregs as a normal argument. – Jester Mar 11 '16 at 00:35
  • I'm adding 8 to get from the address of the popregs function to get to the registers - is that not right? – Mikey Chen Mar 11 '16 at 00:55
  • 2
    It might be right, it might not be. It depends on what code the compiler emits before the asm statement, and that could be anything. You're misusing inline assembly. You either need to write entire function in assembly or do something like Jester said. – Ross Ridge Mar 11 '16 at 04:15

0 Answers0