diff options
author | Mike Frysinger <vapier@gentoo.org> | 2010-02-17 05:44:22 -0500 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2010-03-09 00:30:51 -0500 |
commit | 600482c13d3d3612d71f39d8aaec47f63aafa801 (patch) | |
tree | 87b347917f743a493de71d9655f7f336f4e92c73 /arch/blackfin/kernel | |
parent | e8f263dfd32a784a816fe68956e564f8ede4a9fc (diff) |
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>
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r-- | arch/blackfin/kernel/ptrace.c | 11 | ||||
-rw-r--r-- | arch/blackfin/kernel/signal.c | 3 |
2 files changed, 11 insertions, 3 deletions
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 0618b8287e34..43eb969405d1 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c | |||
@@ -220,12 +220,16 @@ void user_enable_single_step(struct task_struct *child) | |||
220 | { | 220 | { |
221 | struct pt_regs *regs = task_pt_regs(child); | 221 | struct pt_regs *regs = task_pt_regs(child); |
222 | regs->syscfg |= SYSCFG_SSSTEP; | 222 | regs->syscfg |= SYSCFG_SSSTEP; |
223 | |||
224 | set_tsk_thread_flag(child, TIF_SINGLESTEP); | ||
223 | } | 225 | } |
224 | 226 | ||
225 | void user_disable_single_step(struct task_struct *child) | 227 | void user_disable_single_step(struct task_struct *child) |
226 | { | 228 | { |
227 | struct pt_regs *regs = task_pt_regs(child); | 229 | struct pt_regs *regs = task_pt_regs(child); |
228 | regs->syscfg &= ~SYSCFG_SSSTEP; | 230 | regs->syscfg &= ~SYSCFG_SSSTEP; |
231 | |||
232 | clear_tsk_thread_flag(child, TIF_SINGLESTEP); | ||
229 | } | 233 | } |
230 | 234 | ||
231 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 235 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
@@ -401,6 +405,9 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) | |||
401 | 405 | ||
402 | asmlinkage void syscall_trace_leave(struct pt_regs *regs) | 406 | asmlinkage void syscall_trace_leave(struct pt_regs *regs) |
403 | { | 407 | { |
404 | if (test_thread_flag(TIF_SYSCALL_TRACE)) | 408 | int step; |
405 | tracehook_report_syscall_exit(regs, 0); | 409 | |
410 | step = test_thread_flag(TIF_SINGLESTEP); | ||
411 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) | ||
412 | tracehook_report_syscall_exit(regs, step); | ||
406 | } | 413 | } |
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index e60990c0a1f0..28d6f28c058c 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c | |||
@@ -306,7 +306,8 @@ asmlinkage void do_signal(struct pt_regs *regs) | |||
306 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 306 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
307 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 307 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
308 | 308 | ||
309 | tracehook_signal_handler(signr, &info, &ka, regs, 1); | 309 | tracehook_signal_handler(signr, &info, &ka, regs, |
310 | test_thread_flag(TIF_SINGLESTEP)); | ||
310 | } | 311 | } |
311 | 312 | ||
312 | return; | 313 | return; |