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.