[lkml]   [2004]   [Dec]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    Patch in this message
    SubjectRe: ptrace single-stepping change breaks Wine
    On Thu, 30 Dec 2004 09:59:27 -0800 (PST), Davide Libenzi
    <> wrote:
    > On Wed, 29 Dec 2004, Linus Torvalds wrote:
    > > On Wed, 29 Dec 2004, Davide Libenzi wrote:
    > > >
    > > > I think same. My test simply let the function processing to let thru and
    > > > reach the fake signal sending point.
    > >
    > > No, your test-case doesn't even send a signal at all, because your
    > > test-program just uses a PTRACE_SINGLESTEP without any "send signal" - so
    > > "exit_code" will be zero after the debuggee gets released from the
    > > "ptrace_notify()", and the suspect code will never be executed..
    > No no, my test case has nothing to do with the extra signal sent in
    > do_syscall_trace(). But the test I put at the time:
    > - if (!test_thread_flag(TIF_SYSCALL_TRACE))
    > + if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
    > + !test_thread_flag(TIF_SINGLESTEP))
    > return;
    > will make the code to not execute the "return" (in the single step case)
    > and to fall through the point where the signal is sent.

    Using the latest version of the patch on do_syscall_trace(), it still
    doesn't work unless I remove this test. If indeed it's supposed to
    fall through to receive the proper signal, (ie to single step properly
    after an int op), then removing it is wrong, and I won't consider it
    anymore. I also have to use the patch shown below, with a typo-fixed,
    to fix the other problem. I broke it apart from the other because we
    might want to consider it seperately right now.

    I spent some time speaking to my brother about this. He has done his
    own kernel before for an embedded system. He was rather frustrated
    with me trying to find a reason for why a rather simple change broke
    my program. He told me I couldn't have it both ways. However I
    believe that I don't understand the linux code well enough to make
    that conclusion.

    > > The problem I think I see (and which the comment alludes to) is that if
    > > the controlling process continues the debuggee with a signal, we'll be
    > > doing the wrong thing: the code in do_syscall_trace() will take that
    > > signal (in "current->exit_code") and send it as a real signal to the
    > > debuggee, but since it is debugged, it will be caught (again) by the
    > > controlling process, which apparently in the case of Wine gets very
    > > confused.
    > >
    > > So I _think_ the problem happens for the following schenario:
    > > - wine for some reason does a PTRACE_SINGLESTEP over a system call
    > > - after the single-step, wine ends up trying to get the sub-process to
    > > enter a signal handler with ptrace( PTRACE_CONT, ... sig)
    > > - the normal ptrace path (where we trap a signal - see kernel/signal.c
    > > and the "ptrace_stop()" logic) handles this correctly, but
    > > do_syscall_trace() will do a "send_sig()"
    > > - we'll try to handle the signal when returning to the traced process
    > > - now "get_signal_to_deliver()" will invoce the ptrace logic AGAIN, and
    > > call ptrace_stop() for this fake signal, and we'll report a new event
    > > to the controlling process.
    > >
    > > Does this make sense?
    > This might explain what they were seeing, but OTOH it seems that the real
    > cause of their problems is related to something else (according to other
    > emails on this thread).

    Actually, I don't think the vanilla kernel has the code that breaks
    those other wine programs. I just learned of this yesterday and it's
    not related. I believe it's only in fedora core 3 or -ac kernels and
    I use vanilla kernels.


    --- 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;
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to
    More majordomo info at
    Please read the FAQ at
     \ /
      Last update: 2005-03-22 14:09    [W:0.025 / U:27.744 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site