Commit 44e0a901 authored by Paul Mackerras's avatar Paul Mackerras Committed by Linus Torvalds

[PATCH] ppc64: fix single-stepping into/out of signal handlers

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: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b832c335
...@@ -162,7 +162,7 @@ syscall_error_cont: ...@@ -162,7 +162,7 @@ syscall_error_cont:
/* check for syscall tracing or audit */ /* check for syscall tracing or audit */
ld r9,TI_FLAGS(r12) 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 bne- syscall_exit_trace
syscall_exit_trace_cont: syscall_exit_trace_cont:
...@@ -322,7 +322,7 @@ _GLOBAL(ppc64_rt_sigreturn) ...@@ -322,7 +322,7 @@ _GLOBAL(ppc64_rt_sigreturn)
blt syscall_exit blt syscall_exit
clrrdi r4,r1,THREAD_SHIFT clrrdi r4,r1,THREAD_SHIFT
ld r4,TI_FLAGS(r4) 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 beq+ 81f
bl .do_syscall_trace_leave bl .do_syscall_trace_leave
81: b .ret_from_except 81: b .ret_from_except
......
...@@ -318,7 +318,8 @@ void do_syscall_trace_leave(void) ...@@ -318,7 +318,8 @@ void do_syscall_trace_leave(void)
if (unlikely(current->audit_context)) if (unlikely(current->audit_context))
audit_syscall_exit(current, 0); /* FIXME: pass pt_regs */ 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)) && (current->ptrace & PT_PTRACED))
do_syscall_trace(); do_syscall_trace();
} }
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/ptrace.h>
#include <asm/sigcontext.h> #include <asm/sigcontext.h>
#include <asm/ucontext.h> #include <asm/ucontext.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -452,6 +453,9 @@ static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, ...@@ -452,6 +453,9 @@ static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
if (err) if (err)
goto badframe; goto badframe;
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
return; return;
badframe: badframe:
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/ptrace.h>
#include <asm/ppc32.h> #include <asm/ppc32.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ppcdebug.h> #include <asm/ppcdebug.h>
...@@ -700,6 +701,9 @@ static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, ...@@ -700,6 +701,9 @@ static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
regs->trap = 0; regs->trap = 0;
regs->result = 0; regs->result = 0;
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
return; return;
badframe: badframe:
...@@ -863,6 +867,9 @@ static void handle_signal32(unsigned long sig, struct k_sigaction *ka, ...@@ -863,6 +867,9 @@ static void handle_signal32(unsigned long sig, struct k_sigaction *ka,
regs->trap = 0; regs->trap = 0;
regs->result = 0; regs->result = 0;
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
return; return;
badframe: badframe:
......
...@@ -58,6 +58,7 @@ static inline void set_single_step(struct task_struct *task) ...@@ -58,6 +58,7 @@ static inline void set_single_step(struct task_struct *task)
struct pt_regs *regs = task->thread.regs; struct pt_regs *regs = task->thread.regs;
if (regs != NULL) if (regs != NULL)
regs->msr |= MSR_SE; regs->msr |= MSR_SE;
set_ti_thread_flag(task->thread_info, TIF_SINGLESTEP);
} }
static inline void clear_single_step(struct task_struct *task) static inline void clear_single_step(struct task_struct *task)
...@@ -65,6 +66,7 @@ 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; struct pt_regs *regs = task->thread.regs;
if (regs != NULL) if (regs != NULL)
regs->msr &= ~MSR_SE; regs->msr &= ~MSR_SE;
clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP);
} }
#endif /* _PPC64_PTRACE_COMMON_H */ #endif /* _PPC64_PTRACE_COMMON_H */
...@@ -97,6 +97,7 @@ static inline struct thread_info *current_thread_info(void) ...@@ -97,6 +97,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_RUN_LIGHT 6 /* iSeries run light */ #define TIF_RUN_LIGHT 6 /* iSeries run light */
#define TIF_ABI_PENDING 7 /* 32/64 bit switch needed */ #define TIF_ABI_PENDING 7 /* 32/64 bit switch needed */
#define TIF_SYSCALL_AUDIT 8 /* syscall auditing active */ #define TIF_SYSCALL_AUDIT 8 /* syscall auditing active */
#define TIF_SINGLESTEP 9 /* singlestepping active */
/* as above, but as bit values */ /* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
...@@ -108,6 +109,7 @@ static inline struct thread_info *current_thread_info(void) ...@@ -108,6 +109,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_RUN_LIGHT (1<<TIF_RUN_LIGHT) #define _TIF_RUN_LIGHT (1<<TIF_RUN_LIGHT)
#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING) #define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) #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_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
#define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \ #define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment