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:
/* 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
......
......@@ -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();
}
......@@ -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:
......
......@@ -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:
......
......@@ -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 */
......@@ -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 | \
......
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