Commit 304bddb4 authored by Linus Torvalds's avatar Linus Torvalds

x86: be a lot more careful about TF handling.

This should fix Wine for some games that otherwise
seem to think that they run under a debugger.
parent c25f215b
......@@ -42,6 +42,12 @@
*/
#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
static inline struct pt_regs *get_child_regs(struct task_struct *task)
{
void *stack_top = (void *)task->thread.esp0;
return stack_top - sizeof(struct pt_regs);
}
/*
* this routine will get a word off of the processes privileged stack.
* the offset is how far from the base addr as stored in the TSS.
......@@ -140,22 +146,35 @@ static unsigned long getreg(struct task_struct *child,
static void set_singlestep(struct task_struct *child)
{
long eflags;
struct pt_regs *regs = get_child_regs(child);
/*
* Always set TIF_SINGLESTEP - this guarantees that
* we single-step system calls etc.. This will also
* cause us to set TF when returning to user mode.
*/
set_tsk_thread_flag(child, TIF_SINGLESTEP);
eflags = get_stack_long(child, EFL_OFFSET);
put_stack_long(child, EFL_OFFSET, eflags | TRAP_FLAG);
/*
* If TF was already set, don't do anything else
*/
if (regs->eflags & TRAP_FLAG)
return;
/* Set TF on the kernel stack, and set the flag to say so */
regs->eflags |= TRAP_FLAG;
child->ptrace |= PT_DTRACE;
}
static void clear_singlestep(struct task_struct *child)
{
if (child->ptrace & PT_DTRACE) {
long eflags;
/* Always clear TIF_SINGLESTEP... */
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
eflags = get_stack_long(child, EFL_OFFSET);
put_stack_long(child, EFL_OFFSET, eflags & ~TRAP_FLAG);
/* But touch TF only if it was set by us.. */
if (child->ptrace & PT_DTRACE) {
struct pt_regs *regs = get_child_regs(child);
regs->eflags &= ~TRAP_FLAG;
child->ptrace &= ~PT_DTRACE;
}
}
......
......@@ -270,7 +270,6 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
struct pt_regs *regs, unsigned long mask)
{
int tmp, err = 0;
unsigned long eflags;
tmp = 0;
__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
......@@ -292,16 +291,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
err |= __put_user(current->thread.error_code, &sc->err);
err |= __put_user(regs->eip, &sc->eip);
err |= __put_user(regs->xcs, (unsigned int __user *)&sc->cs);
/*
* Iff TF was set because the program is being single-stepped by a
* debugger, don't save that information on the signal stack.. We
* don't want debugging to change state.
*/
eflags = regs->eflags;
if (current->ptrace & PT_DTRACE)
eflags &= ~TF_MASK;
err |= __put_user(eflags, &sc->eflags);
err |= __put_user(regs->eflags, &sc->eflags);
err |= __put_user(regs->esp, &sc->esp_at_signal);
err |= __put_user(regs->xss, (unsigned int __user *)&sc->ss);
......@@ -424,11 +414,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
* The tracer may want to single-step inside the
* handler too.
*/
if (regs->eflags & TF_MASK) {
regs->eflags &= ~TF_MASK;
if (current->ptrace & PT_DTRACE)
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
}
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
......@@ -519,11 +507,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
* The tracer may want to single-step inside the
* handler too.
*/
if (regs->eflags & TF_MASK) {
regs->eflags &= ~TF_MASK;
if (current->ptrace & PT_DTRACE)
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
}
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
......
......@@ -717,9 +717,18 @@ fastcall void do_debug(struct pt_regs * regs, long error_code)
*/
if ((regs->xcs & 3) == 0)
goto clear_TF_reenable;
if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
/*
* Was the TF flag set by a debugger? If so, clear it now,
* so that register information is correct.
*/
if (tsk->ptrace & PT_DTRACE) {
regs->eflags &= ~TF_MASK;
tsk->ptrace &= ~PT_DTRACE;
if (!tsk->ptrace & PT_DTRACE)
goto clear_TF;
}
}
/* Ok, finally something we can handle */
send_sigtrap(tsk, regs, error_code);
......
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