diff options
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 8ce247ac04c..d54c6e53aba 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) | |||
519 | siginfo_t info; | 519 | siginfo_t info; |
520 | int signr; | 520 | int signr; |
521 | 521 | ||
522 | /* It's a lot of work and synchronization to add a new ptrace | ||
523 | * register for GDB to save and restore in order to get | ||
524 | * orig_i0 correct for syscall restarts when debugging. | ||
525 | * | ||
526 | * Although it should be the case that most of the global | ||
527 | * registers are volatile across a system call, glibc already | ||
528 | * depends upon that fact that we preserve them. So we can't | ||
529 | * just use any global register to save away the orig_i0 value. | ||
530 | * | ||
531 | * In particular %g2, %g3, %g4, and %g5 are all assumed to be | ||
532 | * preserved across a system call trap by various pieces of | ||
533 | * code in glibc. | ||
534 | * | ||
535 | * %g7 is used as the "thread register". %g6 is not used in | ||
536 | * any fixed manner. %g6 is used as a scratch register and | ||
537 | * a compiler temporary, but it's value is never used across | ||
538 | * a system call. Therefore %g6 is usable for orig_i0 storage. | ||
539 | */ | ||
522 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) | 540 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) |
523 | restart_syscall = 1; | 541 | regs->u_regs[UREG_G6] = orig_i0; |
524 | else | ||
525 | restart_syscall = 0; | ||
526 | 542 | ||
527 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 543 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
528 | oldset = ¤t->saved_sigmask; | 544 | oldset = ¤t->saved_sigmask; |
@@ -535,8 +551,12 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
535 | * the software "in syscall" bit, directing us to not perform | 551 | * the software "in syscall" bit, directing us to not perform |
536 | * a syscall restart. | 552 | * a syscall restart. |
537 | */ | 553 | */ |
538 | if (restart_syscall && !pt_regs_is_syscall(regs)) | 554 | restart_syscall = 0; |
539 | restart_syscall = 0; | 555 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) { |
556 | restart_syscall = 1; | ||
557 | orig_i0 = regs->u_regs[UREG_G6]; | ||
558 | } | ||
559 | |||
540 | 560 | ||
541 | if (signr > 0) { | 561 | if (signr > 0) { |
542 | if (restart_syscall) | 562 | if (restart_syscall) |