x86 ptrace: block-step fix
The enable_single_step() logic bails out early if TF is already set. That skips some of the bookkeeping that keeps things straight. This makes PTRACE_SINGLEBLOCK break the behavior of a user task that was already setting TF itself in user mode. Fix the bookkeeping to notice the old TF setting as it should. Test case at: http://sources.redhat.com/cgi-bin/cvsweb.cgi/~checkout~/tests/ptrace-tests/tests/step-jump-cont-strict.c?cvsroot=systemtap Signed-off-by: Roland McGrath <roland@redhat.com>
This commit is contained in:
Родитель
a3cf859321
Коммит
6718d0d6da
|
@ -105,6 +105,7 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
|
|||
static int enable_single_step(struct task_struct *child)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(child);
|
||||
unsigned long oflags;
|
||||
|
||||
/*
|
||||
* Always set TIF_SINGLESTEP - this guarantees that
|
||||
|
@ -113,11 +114,7 @@ static int enable_single_step(struct task_struct *child)
|
|||
*/
|
||||
set_tsk_thread_flag(child, TIF_SINGLESTEP);
|
||||
|
||||
/*
|
||||
* If TF was already set, don't do anything else
|
||||
*/
|
||||
if (regs->flags & X86_EFLAGS_TF)
|
||||
return 0;
|
||||
oflags = regs->flags;
|
||||
|
||||
/* Set TF on the kernel stack.. */
|
||||
regs->flags |= X86_EFLAGS_TF;
|
||||
|
@ -126,9 +123,22 @@ static int enable_single_step(struct task_struct *child)
|
|||
* ..but if TF is changed by the instruction we will trace,
|
||||
* don't mark it as being "us" that set it, so that we
|
||||
* won't clear it by hand later.
|
||||
*
|
||||
* Note that if we don't actually execute the popf because
|
||||
* of a signal arriving right now or suchlike, we will lose
|
||||
* track of the fact that it really was "us" that set it.
|
||||
*/
|
||||
if (is_setting_trap_flag(child, regs))
|
||||
if (is_setting_trap_flag(child, regs)) {
|
||||
clear_tsk_thread_flag(child, TIF_FORCED_TF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If TF was already set, check whether it was us who set it.
|
||||
* If not, we should never attempt a block step.
|
||||
*/
|
||||
if (oflags & X86_EFLAGS_TF)
|
||||
return test_tsk_thread_flag(child, TIF_FORCED_TF);
|
||||
|
||||
set_tsk_thread_flag(child, TIF_FORCED_TF);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче