]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] ppc64: fix single-stepping into/out of signal handlers
authorPaul Mackerras <paulus@samba.org>
Fri, 17 Dec 2004 01:19:57 +0000 (17:19 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 17 Dec 2004 01:19:57 +0000 (17:19 -0800)
This is the second of 3 patches from David Woodhouse which fix various
problems with signal handling on ppc64.

The problem that this patch fixes is that a process being single-stepped
will execute one instruction too many in certain cases: when a signal is
delivered, when a signal handler returns, and when a system call
instruction is single-stepped.  This patch fixes it by checking if the
process is being single-stepped in the syscall exit path and on signal
delivery, and stopping it if so.  To avoid slowing down the syscall exit
path in the normal case, we use a bit in the thread_info flags, which can
be tested along with the other bits we already test in the syscall exit
path.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/ppc64/kernel/entry.S
arch/ppc64/kernel/ptrace.c
arch/ppc64/kernel/signal.c
arch/ppc64/kernel/signal32.c
include/asm-ppc64/ptrace-common.h
include/asm-ppc64/thread_info.h

index 2dc052f6a0758199358027278b9c04e7824f2435..74e7d48bc8f39093283df619f2c81fcfcb4332a1 100644 (file)
@@ -162,7 +162,7 @@ syscall_error_cont:
 
        /* check for syscall tracing or audit */
        ld      r9,TI_FLAGS(r12)
-       andi.   r0,r9,_TIF_SYSCALL_T_OR_A
+       andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
        bne-    syscall_exit_trace
 syscall_exit_trace_cont:
 
@@ -322,7 +322,7 @@ _GLOBAL(ppc64_rt_sigreturn)
        blt     syscall_exit
        clrrdi  r4,r1,THREAD_SHIFT
        ld      r4,TI_FLAGS(r4)
-       andi.   r4,r4,_TIF_SYSCALL_T_OR_A
+       andi.   r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
        beq+    81f
        bl      .do_syscall_trace_leave
 81:    b       .ret_from_except
index 0a4011f58f2f336b2cef7152d1f7e3b2662e9369..b3f560bd839ea59f8291ff8494072b5bc92ce7c5 100644 (file)
@@ -318,7 +318,8 @@ void do_syscall_trace_leave(void)
        if (unlikely(current->audit_context))
                audit_syscall_exit(current, 0); /* FIXME: pass pt_regs */
 
-       if (test_thread_flag(TIF_SYSCALL_TRACE)
+       if ((test_thread_flag(TIF_SYSCALL_TRACE)
+            || test_thread_flag(TIF_SINGLESTEP))
            && (current->ptrace & PT_PTRACED))
                do_syscall_trace();
 }
index 82da5a8ea65a14532e9e079cce681f6e775b2dad..c5a952d19ff29d435d8e7e1fd0cbc00dd48e00b3 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/elf.h>
+#include <linux/ptrace.h>
 #include <asm/sigcontext.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -452,6 +453,9 @@ static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
        if (err)
                goto badframe;
 
+       if (test_thread_flag(TIF_SINGLESTEP))
+               ptrace_notify(SIGTRAP);
+
        return;
 
 badframe:
index 42f3bd641760d5a1138a655497cfd75a4ffad220..59a5b6d73976408db37736de1c20f7d989aa8b7b 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/elf.h>
 #include <linux/compat.h>
+#include <linux/ptrace.h>
 #include <asm/ppc32.h>
 #include <asm/uaccess.h>
 #include <asm/ppcdebug.h>
@@ -700,6 +701,9 @@ static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
        regs->trap = 0;
        regs->result = 0;
 
+       if (test_thread_flag(TIF_SINGLESTEP))
+               ptrace_notify(SIGTRAP);
+
        return;
 
 badframe:
@@ -863,6 +867,9 @@ static void handle_signal32(unsigned long sig, struct k_sigaction *ka,
        regs->trap = 0;
        regs->result = 0;
 
+       if (test_thread_flag(TIF_SINGLESTEP))
+               ptrace_notify(SIGTRAP);
+
        return;
 
 badframe:
index 3dbd3e5847b309428f6a368b27e6005eaa788472..af03547f9c7edf4151afbbb3f29d5bbd89fddba6 100644 (file)
@@ -58,6 +58,7 @@ static inline void set_single_step(struct task_struct *task)
        struct pt_regs *regs = task->thread.regs;
        if (regs != NULL)
                regs->msr |= MSR_SE;
+       set_ti_thread_flag(task->thread_info, TIF_SINGLESTEP);
 }
 
 static inline void clear_single_step(struct task_struct *task)
@@ -65,6 +66,7 @@ static inline void clear_single_step(struct task_struct *task)
        struct pt_regs *regs = task->thread.regs;
        if (regs != NULL)
                regs->msr &= ~MSR_SE;
+       clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP);
 }
 
 #endif /* _PPC64_PTRACE_COMMON_H */
index 6a8a4c4c334ddf7a4854e1ebb15eee30e9721b2b..595d67ef4b6f02ad04bd28256cd2c1211a53bb61 100644 (file)
@@ -97,6 +97,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_RUN_LIGHT          6       /* iSeries run light */
 #define TIF_ABI_PENDING                7       /* 32/64 bit switch needed */
 #define TIF_SYSCALL_AUDIT      8       /* syscall auditing active */
+#define TIF_SINGLESTEP         9       /* singlestepping active */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
@@ -108,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_RUN_LIGHT         (1<<TIF_RUN_LIGHT)
 #define _TIF_ABI_PENDING       (1<<TIF_ABI_PENDING)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
+#define _TIF_SINGLESTEP                (1<<TIF_SINGLESTEP)
 #define _TIF_SYSCALL_T_OR_A    (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
 
 #define _TIF_USER_WORK_MASK    (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \