Blackfin: fix single stepping over system calls

On Blackfin systems, the hardware single step exception triggers before
the system call exception, so we need to save this info to process it
later on.  Otherwise, single stepping in userspace misses a few insns
right after the system call.

This is based a bit on the SuperH code added in commit 4b505db9c4c72dbd.

Reported-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h
index 0149c92..e9a5614 100644
--- a/arch/blackfin/include/asm/thread_info.h
+++ b/arch/blackfin/include/asm/thread_info.h
@@ -103,6 +103,7 @@
 #define TIF_FREEZE		6	/* is freezing for suspend */
 #define TIF_IRQ_SYNC		7	/* sync pipeline stage */
 #define TIF_NOTIFY_RESUME	8	/* callback before returning to user */
+#define TIF_SINGLESTEP		9
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -113,6 +114,7 @@
 #define _TIF_FREEZE		(1<<TIF_FREEZE)
 #define _TIF_IRQ_SYNC		(1<<TIF_IRQ_SYNC)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
+#define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index 0618b828..43eb969 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -220,12 +220,16 @@
 {
 	struct pt_regs *regs = task_pt_regs(child);
 	regs->syscfg |= SYSCFG_SSSTEP;
+
+	set_tsk_thread_flag(child, TIF_SINGLESTEP);
 }
 
 void user_disable_single_step(struct task_struct *child)
 {
 	struct pt_regs *regs = task_pt_regs(child);
 	regs->syscfg &= ~SYSCFG_SSSTEP;
+
+	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -401,6 +405,9 @@
 
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
-	if (test_thread_flag(TIF_SYSCALL_TRACE))
-		tracehook_report_syscall_exit(regs, 0);
+	int step;
+
+	step = test_thread_flag(TIF_SINGLESTEP);
+	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall_exit(regs, step);
 }
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index e60990c..28d6f28 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -306,7 +306,8 @@
 			if (test_thread_flag(TIF_RESTORE_SIGMASK))
 				clear_thread_flag(TIF_RESTORE_SIGMASK);
 
-			tracehook_signal_handler(signr, &info, &ka, regs, 1);
+			tracehook_signal_handler(signr, &info, &ka, regs,
+				test_thread_flag(TIF_SINGLESTEP));
 		}
 
 		return;
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 0df5b83..0a9e458 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -642,6 +642,8 @@
 	r7 = [p2+TI_FLAGS];
 	CC = BITTST(r7,TIF_SYSCALL_TRACE);
 	if CC JUMP _sys_trace;
+	CC = BITTST(r7,TIF_SINGLESTEP);
+	if CC JUMP _sys_trace;
 
 	/* Execute the appropriate system call */