If the tracer sets PTRACE_O_TRACEVFORKDONE but not PTRACE_O_TRACEVFORK, clone(CLONE_VFORK) should be reported too, so in this case event must be PTRACE_EVENT_VFORK_DONE.
But we can't return UTRACE_STOP. Since CLONE_VFORK is set, utrace will actually stop the tracee in tracehook_report_clone_complete() path, this is not we want. We return UTRACE_RESUME which ensures ->report_quiesce() will notice ptrace_event_pending() and return UTRACE_STOP later, before return to user-mode. Small problem. PTRACE_O_TRACEVFORKDONE doesn't imply auto-attach, so we have to check it before ptrace_clone_attach(). TODO: cleanup this !!! As expected, this fixes tests/o_tracevforkdone again but the code is still wrong. --- kernel/ptrace.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) --- PU/kernel/ptrace.c~97_CLONE_VFORKDONE 2009-10-17 17:28:10.000000000 +0200 +++ PU/kernel/ptrace.c 2009-10-17 19:37:45.000000000 +0200 @@ -199,6 +199,8 @@ static u32 ptrace_report_clone(enum utra if (clone_flags & CLONE_VFORK) { if (context->options & PTRACE_O_TRACEVFORK) event = PTRACE_EVENT_VFORK; + else if (context->options & PTRACE_O_TRACEVFORKDONE) + event = PTRACE_EVENT_VFORK_DONE; } else if ((clone_flags & CSIGNAL) != SIGCHLD) { if (context->options & PTRACE_O_TRACECLONE) event = PTRACE_EVENT_CLONE; @@ -209,7 +211,7 @@ static u32 ptrace_report_clone(enum utra * Any of these reports implies auto-attaching the new child. * So does CLONE_PTRACE, even with no event to report. */ - if (event || (clone_flags & CLONE_PTRACE)) + if ((event && event != PTRACE_EVENT_VFORK_DONE) || (clone_flags & CLONE_PTRACE)) ptrace_clone_attach(parent, child, context->options); if (!event || (clone_flags & CLONE_UNTRACED)) @@ -218,7 +220,10 @@ static u32 ptrace_report_clone(enum utra set_stop_code(context, event); context->eventmsg = child->pid; - return UTRACE_STOP; + if (event == PTRACE_EVENT_VFORK_DONE) + return UTRACE_REPORT; + else + return UTRACE_STOP; } static inline void set_syscall_code(struct ptrace_context *context, int event)