Commit 2fc7d762 authored by Linus Torvalds's avatar Linus Torvalds Committed by Linus Torvalds

x86: clean up ptrace single-stepping, make PT_DTRACE exact.

(This makes the naming of "DTRACE" purely historical, since
on x86 it now means "single step in progress").
parent 6cff2b97
...@@ -138,6 +138,28 @@ static unsigned long getreg(struct task_struct *child, ...@@ -138,6 +138,28 @@ static unsigned long getreg(struct task_struct *child,
return retval; return retval;
} }
static void set_singlestep(struct task_struct *child)
{
long eflags;
set_tsk_thread_flag(child, TIF_SINGLESTEP);
eflags = get_stack_long(child, EFL_OFFSET);
put_stack_long(child, EFL_OFFSET, eflags | TRAP_FLAG);
child->ptrace |= PT_DTRACE;
}
static void clear_singlestep(struct task_struct *child)
{
if (child->ptrace & PT_DTRACE) {
long eflags;
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
eflags = get_stack_long(child, EFL_OFFSET);
put_stack_long(child, EFL_OFFSET, eflags & ~TRAP_FLAG);
child->ptrace &= ~PT_DTRACE;
}
}
/* /*
* Called by kernel/ptrace.c when detaching.. * Called by kernel/ptrace.c when detaching..
* *
...@@ -145,11 +167,7 @@ static unsigned long getreg(struct task_struct *child, ...@@ -145,11 +167,7 @@ static unsigned long getreg(struct task_struct *child,
*/ */
void ptrace_disable(struct task_struct *child) void ptrace_disable(struct task_struct *child)
{ {
long tmp; clear_singlestep(child);
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
} }
/* /*
...@@ -388,10 +406,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -388,10 +406,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
} }
break; break;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: { /* restart after signal. */ case PTRACE_CONT: /* restart after signal. */
long tmp;
ret = -EIO; ret = -EIO;
if ((unsigned long) data > _NSIG) if ((unsigned long) data > _NSIG)
break; break;
...@@ -401,56 +417,39 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -401,56 +417,39 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
else { else {
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
} }
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = data; child->exit_code = data;
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; clear_singlestep(child);
put_stack_long(child, EFL_OFFSET,tmp);
wake_up_process(child); wake_up_process(child);
ret = 0; ret = 0;
break; break;
}
/* /*
* make the child exit. Best I can do is send it a sigkill. * 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 * perhaps it should be put in the status that it wants to
* exit. * exit.
*/ */
case PTRACE_KILL: { case PTRACE_KILL:
long tmp;
ret = 0; ret = 0;
if (child->exit_state == EXIT_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; clear_singlestep(child);
put_stack_long(child, EFL_OFFSET, tmp);
wake_up_process(child); wake_up_process(child);
break; break;
}
case PTRACE_SINGLESTEP: { /* set the trap flag. */
long tmp;
case PTRACE_SINGLESTEP: /* set the trap flag. */
ret = -EIO; ret = -EIO;
if ((unsigned long) data > _NSIG) if ((unsigned long) data > _NSIG)
break; break;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
if ((child->ptrace & PT_DTRACE) == 0) { set_singlestep(child);
/* Spurious delayed TF traps may occur */
child->ptrace |= PT_DTRACE;
}
tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
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);
ret = 0; ret = 0;
break; break;
}
case PTRACE_DETACH: case PTRACE_DETACH:
/* detach a process that was attached. */ /* detach a process that was attached. */
......
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