Skip to content

Commit

Permalink
sh: Clear UBC when not in use.
Browse files Browse the repository at this point in the history
This takes care of tearing down the UBC so it's not inadvertently
left configured at the next context switch time. Failure to do
this results in spurious SIGTRAPs in certain debug sequences.

Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
  • Loading branch information
Stuart Menefy authored and Paul Mundt committed Mar 5, 2007
1 parent 20b0f65 commit 9432f96
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 13 deletions.
2 changes: 1 addition & 1 deletion arch/sh/kernel/entry-common.S
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ work_resched:
syscall_exit_work:
! r0: current_thread_info->flags
! r8: current_thread_info
tst #_TIF_SYSCALL_TRACE, r0
tst #_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP, r0
bt/s work_pending
tst #_TIF_NEED_RESCHED, r0
#ifdef CONFIG_TRACE_IRQFLAGS
Expand Down
45 changes: 33 additions & 12 deletions arch/sh/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
* SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
*
*/

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
Expand All @@ -20,8 +19,7 @@
#include <linux/slab.h>
#include <linux/security.h>
#include <linux/signal.h>

#include <asm/io.h>
#include <linux/io.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
Expand Down Expand Up @@ -59,14 +57,31 @@ static inline int put_stack_long(struct task_struct *task, int offset,
return 0;
}

static void ptrace_disable_singlestep(struct task_struct *child)
{
clear_tsk_thread_flag(child, TIF_SINGLESTEP);

/*
* Ensure the UBC is not programmed at the next context switch.
*
* Normally this is not needed but there are sequences such as
* singlestep, signal delivery, and continue that leave the
* ubc_pc non-zero leading to spurious SIGTRAPs.
*/
if (child->thread.ubc_pc != 0) {
ubc_usercnt -= 1;
child->thread.ubc_pc = 0;
}
}

/*
* Called by kernel/ptrace.c when detaching..
*
* Make sure single step bits etc are not set.
*/
void ptrace_disable(struct task_struct *child)
{
/* nothing to do.. */
ptrace_disable_singlestep(child);
}

long arch_ptrace(struct task_struct *child, long request, long addr, long data)
Expand All @@ -76,7 +91,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)

switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: {
unsigned long tmp;
int copied;
Expand All @@ -94,7 +109,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
unsigned long tmp;

ret = -EIO;
if ((addr & 3) || addr < 0 ||
if ((addr & 3) || addr < 0 ||
addr > sizeof(struct user) - 3)
break;

Expand Down Expand Up @@ -129,7 +144,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)

case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
if ((addr & 3) || addr < 0 ||
if ((addr & 3) || addr < 0 ||
addr > sizeof(struct user) - 3)
break;

Expand All @@ -156,21 +171,25 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

ptrace_disable_singlestep(child);

child->exit_code = data;
wake_up_process(child);
ret = 0;
break;
}

/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL: {
ret = 0;
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
ptrace_disable_singlestep(child);
child->exit_code = SIGKILL;
wake_up_process(child);
break;
Expand All @@ -196,6 +215,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ubc_usercnt += 1;
child->thread.ubc_pc = pc;

set_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = data;
/* give it a chance to run. */
wake_up_process(child);
Expand Down Expand Up @@ -248,14 +268,15 @@ asmlinkage void do_syscall_trace(void)
{
struct task_struct *tsk = current;

if (!test_thread_flag(TIF_SYSCALL_TRACE))
if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
!test_thread_flag(TIF_SINGLESTEP))
return;
if (!(tsk->ptrace & PT_PTRACED))
return;
/* the 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0));
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
!test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));

/*
* this isn't the same as continuing with a signal, but it will do
Expand Down
2 changes: 2 additions & 0 deletions include/asm-sh/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */
#define TIF_SINGLESTEP 5 /* singlestepping active */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 18
Expand All @@ -121,6 +122,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_FREEZE (1<<TIF_FREEZE)
Expand Down

0 comments on commit 9432f96

Please sign in to comment.