sh: Clear UBC when not in use.
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>
This commit is contained in:
parent
20b0f65d35
commit
9432f96803
|
@ -224,7 +224,7 @@ work_resched:
|
||||||
syscall_exit_work:
|
syscall_exit_work:
|
||||||
! r0: current_thread_info->flags
|
! r0: current_thread_info->flags
|
||||||
! r8: current_thread_info
|
! r8: current_thread_info
|
||||||
tst #_TIF_SYSCALL_TRACE, r0
|
tst #_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP, r0
|
||||||
bt/s work_pending
|
bt/s work_pending
|
||||||
tst #_TIF_NEED_RESCHED, r0
|
tst #_TIF_NEED_RESCHED, r0
|
||||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
* SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
|
* SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
@ -20,8 +19,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/signal.h>
|
#include <linux/signal.h>
|
||||||
|
#include <linux/io.h>
|
||||||
#include <asm/io.h>
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
@ -59,6 +57,23 @@ static inline int put_stack_long(struct task_struct *task, int offset,
|
||||||
return 0;
|
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..
|
* Called by kernel/ptrace.c when detaching..
|
||||||
*
|
*
|
||||||
|
@ -66,7 +81,7 @@ static inline int put_stack_long(struct task_struct *task, int offset,
|
||||||
*/
|
*/
|
||||||
void ptrace_disable(struct task_struct *child)
|
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)
|
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||||
|
@ -156,6 +171,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||||
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||||
else
|
else
|
||||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||||
|
|
||||||
|
ptrace_disable_singlestep(child);
|
||||||
|
|
||||||
child->exit_code = data;
|
child->exit_code = data;
|
||||||
wake_up_process(child);
|
wake_up_process(child);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -171,6 +189,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
|
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
|
||||||
break;
|
break;
|
||||||
|
ptrace_disable_singlestep(child);
|
||||||
child->exit_code = SIGKILL;
|
child->exit_code = SIGKILL;
|
||||||
wake_up_process(child);
|
wake_up_process(child);
|
||||||
break;
|
break;
|
||||||
|
@ -196,6 +215,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||||
ubc_usercnt += 1;
|
ubc_usercnt += 1;
|
||||||
child->thread.ubc_pc = pc;
|
child->thread.ubc_pc = pc;
|
||||||
|
|
||||||
|
set_tsk_thread_flag(child, TIF_SINGLESTEP);
|
||||||
child->exit_code = data;
|
child->exit_code = data;
|
||||||
/* give it a chance to run. */
|
/* give it a chance to run. */
|
||||||
wake_up_process(child);
|
wake_up_process(child);
|
||||||
|
@ -248,14 +268,15 @@ asmlinkage void do_syscall_trace(void)
|
||||||
{
|
{
|
||||||
struct task_struct *tsk = current;
|
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;
|
return;
|
||||||
if (!(tsk->ptrace & PT_PTRACED))
|
if (!(tsk->ptrace & PT_PTRACED))
|
||||||
return;
|
return;
|
||||||
/* the 0x80 provides a way for the tracing parent to distinguish
|
/* the 0x80 provides a way for the tracing parent to distinguish
|
||||||
between a syscall stop and SIGTRAP delivery */
|
between a syscall stop and SIGTRAP delivery */
|
||||||
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
|
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
|
||||||
? 0x80 : 0));
|
!test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this isn't the same as continuing with a signal, but it will do
|
* this isn't the same as continuing with a signal, but it will do
|
||||||
|
|
|
@ -111,6 +111,7 @@ static inline struct thread_info *current_thread_info(void)
|
||||||
#define TIF_SIGPENDING 2 /* signal pending */
|
#define TIF_SIGPENDING 2 /* signal pending */
|
||||||
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
|
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
|
||||||
#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */
|
#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_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_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
|
||||||
#define TIF_MEMDIE 18
|
#define TIF_MEMDIE 18
|
||||||
|
@ -121,6 +122,7 @@ static inline struct thread_info *current_thread_info(void)
|
||||||
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
|
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
|
||||||
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
|
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
|
||||||
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
|
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
|
||||||
|
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
|
||||||
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
|
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
|
||||||
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
|
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
|
||||||
#define _TIF_FREEZE (1<<TIF_FREEZE)
|
#define _TIF_FREEZE (1<<TIF_FREEZE)
|
||||||
|
|
Loading…
Reference in New Issue