BSD DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


IRIX Binary Compatibility, Part 4
Pages: 1, 2, 3, 4

The next problem where our emulation may not be accurate enough is probably the stack layout and CPU registers on signal handler invocation. If the IRIX process makes any assumption about them, we can fail. The method for checking stack and CPU register contents on signal handler invocation is simple, it is exactly the same we used on program startup.



We will use it on the following test program:

/* signal11.c -- a simple sigaction(2) tester */
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void func (int, siginfo_t *, void *);

int main (int argc, char** argv) {
        struct sigaction sa;
        sigset_t ss;

        bzero(&ss, sizeof(ss));

        sa.sa_handler = NULL;
        sa.sa_mask = ss;
        sa.sa_flags = 0;
        sa.sa_sigaction = *func;

        if (sigaction(SIGHUP, &sa, NULL))
                printf("sigaction() failed\n");
        kill(getpid(), 1);
        return 0;
}

void func (int sig, siginfo_t *si, void *v) {
        printf("signal handler\n");
        return 0;
}

Then, using gdb on IRIX, we can break at the beginning of the signal handler:

$ gdb ./signal11
Breakpoint 1 at 0x400e38: file signal11.c, line 27.

(gdb) r
Starting program: /tmp/signal11

Program received signal SIGHUP, Hangup.
0xfa455a4 in _kill () at kill.s:15
15      kill.s: No such file or directory.
(gdb) c
Continuing.

Breakpoint 1, func () at signal11.c:27
27              printf("signal handler");
(gdb) info registers
          zero       at       v0       v1       a0       a1       a2       a3
 R0   00000000 fffffffe 00000000 00023dd5 00000001 00000000 7fff2b60 00400e28
            t0       t1       t2       t3       t4       t5       t6       t7
 R8   0fb4f9b0 00000000 0fb4e931 00000042 00000001 0000001d 0faee284 ffffffff
            s0       s1       s2       s3       s4       s5       s6       s7
 R16  00023f14 7fff2f74 7fff2f7c 7fff2fc8 00000000 00000000 00000000 00000000
            t8       t9       k0       k1       gp       sp       fp       ra
 R24  00400e10 00400e28 00000000 00000014 1000c040 7fff2b10 00000000 0faee2e8
            pc    cause      bad       hi       lo      fsr      fir
      00400e38 00000024 00000000 0000005c 0000015b 00000000 00000000
(gdb) x/32w $sp
0x7fff2b10:     0x00000000      0x00000000      0x00000000      0x00000000
0x7fff2b20:     0x00000000      0x00000000      0x00000000      0x00000000
0x7fff2b30:     0x00000000      0x00000000      0x00000000      0x00000000
0x7fff2b40:     0x00000000      0x00000000      0x00000000      0x0fb4f9b0
0x7fff2b50:     0x00000000      0x00000001      0x7fff2b60      0x7fff2b60
0x7fff2b60:     0xffffffff      0x00000000      0x00000000      0x0fa455a4
0x7fff2b70:     0x00000000      0x00000000      0x00000000      0x00000000
0x7fff2b80:     0x00000000      0x00000000      0x00000000      0x00023dd5

In the A0, A1 and A2 registers we have the arguments to the signal handler. A2 points to the struct sigcontext, and we can therefore start to figure out how the stack is set up for signal delivery.

It is interesting to discover where the different pointers go. For example, at 0x7fff2b3c, we have a pointer to 0x0fb4f9b0. gdb can tells us it points to:

errno: (gdb) x/1w 0x0fb4f9b0 0xfb4f9b0 <errno>:  0x00000000

By running the same program with SA_SIGINFO enabled, we have a slightly different result (now A2 points to 0x7fff2b10)

0x7fff2ac0:     0x00000000      0x00000000      0x00000000      0x00000000
0x7fff2ad0:     0x00000000      0x00000000      0x00000000      0x00000000
0x7fff2ae0:     0x00000000      0x00000000      0x00000000      0x00000000
0x7fff2af0:     0x00000000      0x00000000      0x00000000      0x0fb4f9b0
0x7fff2b00:     0x00000000      0x80000001      0x00000000      0x7fff2b10
0x7fff2b10:     0x0000000f      0x00000000      0x00000000      0x00000000
0x7fff2b20:     0x00000000      0x00000000      0x7fff0000      0x00006b58
0x7fff2b30:     0x00000000      0x00000000      0x00000000      0x00000000

Starting at 0x7fff2b10, we now have a struct irix_ucontext. The big difference is that at 0x7fff2b08 we now have a NULL pointer whereas we had a pointer to the struct irix_sigcontext. At 0x7fff2b04 we have the signal number. We end up with the following signal stack frame:

struct irix_sigframe {
     int isf_pad1[7];
     int *isf_uep;   /* 0x7fff2afc Pointer to errno in userspace */
     int isf_errno;  /* 0x7fff2b00 errno value */
     int isf_signo;  /* 0x7fff2b04 signal number */
     struct irix_sigcontext *isf_scp; /* 0x7fff2b08 sigcontext pointer */
     struct irix_ucontext *isf_ucp;   /* 0x7fff2b0c ucontext pointer */
     union {                          /* 0x7fff2b10 sigcontext/ucontext */
         struct irix_ucontext iuc;
         struct irix_sigcontext isc;
     } isf_ctx;
};

Note that it is impossible yet to guess that the isf_errno field holds the errno value. We will discover this a bit later.

Pages: 1, 2, 3, 4

Next Pagearrow





Sponsored by: