diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-12-20 20:32:03 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-12-20 20:32:11 +0100 |
commit | d87f69a16eb2cb96459117b06949a560679002e4 (patch) | |
tree | bbb55b2bd2b6c9e8bd4067aa3279783cb6bd9028 /arch/sparc/kernel/signal_32.c | |
parent | 124ba9403318d834ef21bcd899c22c870708d2c4 (diff) | |
parent | 384703b8e6cd4c8ef08512e596024e028c91c339 (diff) | |
download | op-kernel-dev-d87f69a16eb2cb96459117b06949a560679002e4.zip op-kernel-dev-d87f69a16eb2cb96459117b06949a560679002e4.tar.gz |
Merge commit 'v3.2-rc6' into perf/core
Merge reason: Update with the latest fixes.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/sparc/kernel/signal_32.c')
-rw-r--r-- | arch/sparc/kernel/signal_32.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 8ce247a..d54c6e5 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -519,10 +519,26 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) siginfo_t info; int signr; + /* It's a lot of work and synchronization to add a new ptrace + * register for GDB to save and restore in order to get + * orig_i0 correct for syscall restarts when debugging. + * + * Although it should be the case that most of the global + * registers are volatile across a system call, glibc already + * depends upon that fact that we preserve them. So we can't + * just use any global register to save away the orig_i0 value. + * + * In particular %g2, %g3, %g4, and %g5 are all assumed to be + * preserved across a system call trap by various pieces of + * code in glibc. + * + * %g7 is used as the "thread register". %g6 is not used in + * any fixed manner. %g6 is used as a scratch register and + * a compiler temporary, but it's value is never used across + * a system call. Therefore %g6 is usable for orig_i0 storage. + */ if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) - restart_syscall = 1; - else - restart_syscall = 0; + regs->u_regs[UREG_G6] = orig_i0; if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; @@ -535,8 +551,12 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) * the software "in syscall" bit, directing us to not perform * a syscall restart. */ - if (restart_syscall && !pt_regs_is_syscall(regs)) - restart_syscall = 0; + restart_syscall = 0; + if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) { + restart_syscall = 1; + orig_i0 = regs->u_regs[UREG_G6]; + } + if (signr > 0) { if (restart_syscall) |