This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Bad unwinder data for __kernel_sigtramp_rt64 in PPC 64 vDSO corrupts Condition Register
- From: Andrew Haley <aph-gcc at littlepinkcloud dot COM>
- To: Alan Modra <amodra at au dot ibm dot com>, Benjamin Herrenschmuidt <benh at kernel dot crashing dot org>
- Cc: jakub at redhat dot com, gcc at gcc dot gnu dot org, Deepak Bhole <dbhole at redhat dot com>
- Date: Tue, 16 Oct 2007 18:02:13 +0100
- Subject: Bad unwinder data for __kernel_sigtramp_rt64 in PPC 64 vDSO corrupts Condition Register
The symptom is that if you segfault and then throw an exception in the
segfault handler call-saved fields in the Condition Register are
corrupted.
The reason is that the unwinder data for CR in the vDSO is wrong. The
line that affects the CR is here in
arch/powerpc/kernel/vdso64/sigtramp.S:
rsave (70, 38*RSIZE) /* cr */
This restores a 64-bit register from offset 38 in the sigcontext
register save area to DWARF Column 70. This much is correct...
Unfortunately, gcc saves and restores only the *least significant*
32-bit half of CR on the stack. As this is a big-endian machine, the
result is that when unwinding __kernel_sigtramp_rt64 the correctly
saved CR is written to the upper half of the word on the stack, not
the lower half, and the saved CR is overwritten with zeroes.
It is not immediately clear to me how to fix this: I think you would
need to find a DWARF expression that copies a halfword value.
Test case attached. Tested on Kernel 2.6.18-8.1.10.el5.
Andrew.
#include <signal.h>
#include <cstddef>
#include <cstdio>
class SegfaultException
{
};
void catch_segv (int)
{
throw new SegfaultException;
}
void
segfault (int *p)
{
fprintf (stderr, "%n", *p);
}
int main(int argc, char **argv)
{
unsigned long cr, cr2;
__asm__ __volatile__
("mtcrf 8, %0" : : "r" (0x2000): "cr4");
struct sigaction sa;
sa.sa_handler = catch_segv;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_NODEFER;
sigaction (SIGSEGV, &sa, NULL);
__asm__ __volatile__
("mfcr %0" : "=r" (cr));
fprintf (stderr, "cr = 0x%x\n", cr & 0xfff000);
try
{
segfault(NULL);
}
catch (SegfaultException *a)
{
}
__asm__ __volatile__
("mfcr %0" : "=r" (cr));
fprintf (stderr, "cr = 0x%x\n", cr & 0xfff000);
return 0;
}