On Wed, 29 Dec 2004 16:44:05 -0800 (PST), Linus Torvalds torvalds@osdl.org wrote:
That still leaves the problem of the clearing of TF_MASK. I _appears_ that the problem is that TF was set both by Wine doing a PTRACE_SINGLESTEP (since PT_DTRACE is set) _and_ the application having TF enabled in eflags from before (since it seems to want to keep it enabled).
How about something like the attachment for the TF_MASK issue (replacing your "don't clear" code)? The comments should make the intention pretty obvious, but I have equally obviously not actually _tested_ any of this..
The following patch works for me. I still have to remove TIF_SINGLESTEP test. I also went ahead and tried adding the other fix on the ptrace_notify call and _TIF_WORK_MASK, but for some reason, changing _TIF_WORK_MASK seems to break the program now. This patch does fix the TF clearing problem.
Jesse
--- linux/arch/i386/kernel/ptrace.c 2004-12-29 14:10:34.000000000 -0700 +++ linux-mod/arch/i386/kernel/ptrace.c 2004-12-29 20:50:00.000000000 -0700 @@ -142,18 +142,31 @@ { long eflags;
+ /* + * Always set TIF_SINGLESTEP - this guarantees that + * we single-step system calls etc.. + */ set_tsk_thread_flag(child, TIF_SINGLESTEP); + + /* + * If TF was already set, don't do anything else + */ eflags = get_stack_long(child, EFL_OFFSET); + if (eflags & TRAP_FLAG) + return; put_stack_long(child, EFL_OFFSET, eflags | TRAP_FLAG); child->ptrace |= PT_DTRACE; }
static void clear_singlestep(struct task_struct *child) { + /* Always clear TIF_SINGLESTEP... */ + clear_tsk_thread_flag(child, TIF_SINGLESTEP); + + /* But touch TF only if it was set by us.. */ 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; @@ -568,15 +581,13 @@ audit_syscall_exit(current, regs->eax); }
- if (!test_thread_flag(TIF_SYSCALL_TRACE) && - !test_thread_flag(TIF_SINGLESTEP)) + if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; if (!(current->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) && - !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0)); + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
/* * this isn't the same as continuing with a signal, but it will do