Re: vfork

From: Mike Coleman (mkc@kc.net)
Date: Sat Jan 01 2000 - 20:02:05 EST


torvalds@transmeta.com (Linus Torvalds) writes:
> Add another flag.. Alternatively, the tracer could always do something
> like this with the current __WCLONE semantics:
>
> if (wait4(..normal..) >= 0 || wait4(.. __WCLONE ..) >= 0) {
> ...
> }

I don't see how that works unless both wait4's are WNOHANG. For example, we
could end up hanging in the first wait4, even though a clone child is
available to be waited on immediately. I've added the new flag __WALL to wait
for all children at once.

In addition to what's already been mentioned, one more change seems to be
needed to trace across clone/fork/vfork: a way to find out the original ppid
of the new child. We could look at the syscall return value, but this
requires playing a lot of tricks, and in the CLONE_VFORK case is basically
impossible (since the return value is not given until the child has already
made significant headway).

I was hoping to get the value from /proc/<n>/{stat,status}, but the parent pid
is reported there instead of the original parent pid. IMHO, this is wrong.
As much as possible, traced processes should look just like untraced
processes; to the degree that they're different, you end up with Heisenbugs.
Tools that really need to know that the tracing is going on should have to try
a little harder to observe it--anywhere that a single ppid is given, the
original ppid is generally the one that ought to be supplied.

Until (or instead of) that change, I've added a new ptrace subcommand GETPPID,
which returns the original ppid. With these changes, my (as yet unreleased)
tool is able to trace across fork/vfork/clone, at least for small test
programs, by rewriting these calls to clone and adding the CLONE_PTRACE flag.

--Mike

--- ./kernel/exit.c-dist Thu Nov 25 23:06:48 1999
+++ ./kernel/exit.c Thu Dec 30 02:06:48 1999
@@ -451,7 +451,7 @@
         DECLARE_WAITQUEUE(wait, current);
         struct task_struct *p;
 
- if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
+ if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL))
                 return -EINVAL;
 
         add_wait_queue(&current->wait_chldexit,&wait);
@@ -470,8 +470,13 @@
                         if (p->pgrp != -pid)
                                 continue;
                 }
- /* wait for cloned processes iff the __WCLONE flag is set */
- if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+ /* Wait for all children (clone and not) if __WALL is set;
+ * otherwise, wait for clone children *only* if __WCLONE is
+ * set; otherwise, wait for non-clone children *only*. (Note:
+ * A "clone" child here is one that reports to its parent
+ * using a signal other than SIGCHLD.) */
+ if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+ && !(options & __WALL))
                         continue;
                 flag = 1;
                 switch (p->state) {
--- ./arch/i386/kernel/ptrace.c-dist Thu Dec 30 00:06:15 1999
+++ ./arch/i386/kernel/ptrace.c Thu Dec 30 03:19:13 1999
@@ -448,6 +448,12 @@
                         goto out;
                   };
 
+ case PTRACE_GETPPID: { /* Who's your daddy? */
+ unsigned long ppid = child->p_opptr->pid;
+ ret = put_user(ppid, (unsigned long *) data);
+ goto out;
+ }
+
                 default:
                         ret = -EIO;
                         goto out;
--- ./kernel/fork.c-dist Thu Nov 25 23:07:07 1999
+++ ./kernel/fork.c Thu Dec 23 23:56:03 1999
@@ -646,8 +646,11 @@
         p->run_list.next = NULL;
         p->run_list.prev = NULL;
 
- if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT))
- p->p_pptr = p->p_opptr = current;
+ if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT)) {
+ p->p_opptr = current;
+ if (!(current->flags & PF_PTRACED))
+ p->p_pptr = current;
+ }
         p->p_cptr = NULL;
         init_waitqueue_head(&p->wait_chldexit);
         p->vfork_sem = NULL;
--- ./include/linux/wait.h-dist Thu Dec 30 00:00:25 1999
+++ ./include/linux/wait.h Thu Dec 30 00:00:27 1999
@@ -4,6 +4,7 @@
 #define WNOHANG 0x00000001
 #define WUNTRACED 0x00000002
 
+#define __WALL 0x40000000
 #define __WCLONE 0x80000000
 
 #ifdef __KERNEL__
--- ./include/asm-i386/ptrace.h-dist Thu Dec 30 00:15:46 1999
+++ ./include/asm-i386/ptrace.h Thu Dec 30 00:15:49 1999
@@ -47,6 +47,8 @@
 #define PTRACE_GETFPREGS 14
 #define PTRACE_SETFPREGS 15
 
+#define PTRACE_GETPPID 20
+
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
 #define instruction_pointer(regs) ((regs)->eip)
--- ./arch/i386/kernel/entry.S-dist Mon Dec 27 23:28:14 1999
+++ ./arch/i386/kernel/entry.S Mon Dec 27 23:44:45 1999
@@ -180,6 +180,8 @@
         call SYMBOL_NAME(schedule_tail)
         addl $4, %esp
         GET_CURRENT(%ebx)
+ testb $0x20,flags(%ebx) # PF_TRACESYS
+ jne tracesys_exit # need to set eax first??
         jmp ret_from_sys_call
 
 /*

-- 
Any sufficiently adverse technology is indistinguishable from Microsoft.

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Jan 01 2000 - 23:11:58 EST