|
@@ -529,11 +529,17 @@ 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.
|
|
|
+ *
|
|
|
+ * However, we luckily can use the fact that several registers
|
|
|
+ * are volatile across system calls. One such register is
|
|
|
+ * %g2, so use that as a place to save away orig_i0.
|
|
|
+ */
|
|
|
if (pt_regs_is_syscall(regs) &&
|
|
|
- (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
|
|
|
- restart_syscall = 1;
|
|
|
- } else
|
|
|
- restart_syscall = 0;
|
|
|
+ (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
|
|
|
+ regs->u_regs[UREG_G2] = orig_i0;
|
|
|
|
|
|
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
|
|
|
oldset = ¤t->saved_sigmask;
|
|
@@ -542,22 +548,20 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
|
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
if (test_thread_flag(TIF_32BIT)) {
|
|
|
- extern void do_signal32(sigset_t *, struct pt_regs *,
|
|
|
- int restart_syscall,
|
|
|
- unsigned long orig_i0);
|
|
|
- do_signal32(oldset, regs, restart_syscall, orig_i0);
|
|
|
+ extern void do_signal32(sigset_t *, struct pt_regs *);
|
|
|
+ do_signal32(oldset, regs);
|
|
|
return;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
|
|
|
|
|
- /* If the debugger messes with the program counter, it clears
|
|
|
- * 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->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
|
|
|
+ restart_syscall = 1;
|
|
|
+ orig_i0 = regs->u_regs[UREG_G2];
|
|
|
+ }
|
|
|
|
|
|
if (signr > 0) {
|
|
|
if (restart_syscall)
|