[parisc-linux] signal handling problems (32 bit kernel)
Richard Hirst
rhirst@linuxcare.com
Mon, 20 Nov 2000 17:58:38 +0000
Hi,
Following on from my problems with SEGV last week, I've come up with
a few signal handling issues:
=============================================================
parisc:signal.c
/* Possibly bogus. */
#warning XXX FIXME probably bogus -PB
/* I think this is bogus -- it'll cause the first instn of the
* signal handler to be executed twice! Better might be to
* set iaoq[0] to one of the NOPs in the trampoline. -PB
*/
regs->iaoq[0] = (unsigned long) haddr | 3;
regs->iaoq[1] = (unsigned long) haddr | 3;
This causes real problems if the signal handler is a dynamic object
which has not yet been resolved; in that case the signal handler
points at the b,l instr in the following at the end of the .plt:
2700: 0e 80 10 96 ldw 0(sr0,r20),r22
2704: ea c0 c0 00 bv r0(r22)
2708: 0e 88 10 95 ldw 4(sr0,r20),r21
270c: ea 9f 1f dd b,l 2700 <__DTOR_END__+0x54>,r20
2710: d6 80 1c 1e depwi 0,31,2,r20
typically that results in a misalligned access on the first ldw
as r20 is screwed.
I've fixed that by setting iaoq[1] = iaoq[0]+4. Is that OK, or
should we use the NOP approach in the comment above?
=============================================================
If a program gets a SEGV, fixes the cause of it in its signal
handler, and returns, then the faulting instruction is not rerun.
I think that's wrong (differs from m68k anyway).
=============================================================
Set the following program running:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int v[8];
void (* fp)(int);
void sig_handler(int sig)
{
}
void poke(int i)
{
v[0] = i; v[1] = i; v[2] = i; v[3] = i;
v[4] = i; v[5] = i; v[6] = i; v[7] = i;
}
int main()
{
int j, i = 0;
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = sig_handler;
sigaction(SIGUSR1, &act, NULL);
fp = sig_handler;
fp(0);
printf("I am %d\n", getpid());
while (1) {
poke (++i);
j = v[7];
if (j != i)
printf("Wah!\n");
}
}
and then in another terminal do 'kill -USR1 <pid>'. The program
either goes 'Wah!', gives a SEGV, or works. That seems to be because
%r1 is corrupted while processing the signal. The signal handler ends
with a syscall (rt_sigreturn_wrapper), and %r1, at least, is not saved
and restored over the syscall. %r31 also appears to get corrupted, as
it is used in the final branch of the syscall return.
Richard