On Linux MMU architectures this traces vfork children without changing
their behaviour to fork (which is quite a big change even though all
applications are supposed to not care).  On Linux no-MMU architectures
it allows child processes to be traced.  Before this, all attempts to
trace non-thread children got stuck at vfork.  If we're really lucky
and the kernel is sensible, this might let us trace CLONE_NEWPID
grandchildren too.

* util.c [LINUX] (setbpt): When forking, try to enable the
PTRACE_EVENT_{FORK,VFORK,CLONE} events using PTRACE_SETOPTIONS.  If
successful, instead of converting fork and vfork to clone equivalents,
and vfork to fork, just leave them as they are.  Always return with
tcp->u_arg[arg0_index] set to appropriate clone flags in all cases,
even if clone wasn't actually used.

Signed-off-by: Jamie Lokier <ja...@shareable.org>
---
 util.c |   53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/util.c b/util.c
index 0c4a882..beb397e 100644
--- a/util.c
+++ b/util.c
@@ -1517,6 +1517,59 @@ setbpt(struct tcb *tcp)
                return -1;
        }
 
+#  ifdef PTRACE_EVENT_FORK
+       /*
+        * If are able to set these options, we don't need a
+        * breakpoint.  FIXME: Kernel bugs mean we might need to check
+        * the kernel version number.  See Red Hat Bugzilla bug 246330
+        * - "ptrace looses track of a forked child".  It says it was
+        * broken for a certain range of versions.  See also Red Had
+        * Bugzilla bug 162774 - "strace ignores int3 SIGTRAP" It
+        * includes a patch, and mentions kernels, and a comment in
+        * the patch about when PTRACE_O_TRACESYSGOOD doesn't work
+        * completely, which might be related.
+        */
+       if (ptrace (PTRACE_SETOPTIONS, tcp->pid, (void *) 1,
+                   (long) (PTRACE_O_TRACEFORK
+                           | PTRACE_O_TRACEVFORK
+                           | PTRACE_O_TRACECLONE)) == 0) {
+               /*
+                * Save the clone flags, or fake them, in case no
+                * event is received and internal_fork_child() needs to be
+                * called with these flags.
+                */
+               switch (real_scno) {
+#   ifdef SYS_vfork
+               case SYS_vfork:
+                       tcp->u_arg[arg0_index] = CLONE_VM|CLONE_VFORK|SIGCHLD;
+                       return 0;
+#   endif
+#   ifdef SYS_fork
+               case SYS_fork:
+                       tcp->u_arg[arg0_index] = SIGCHLD;
+                       return 0;
+#   endif
+
+               default:        /* clone, clone2 */
+                       /*
+                        * No breakpoint, but we still need to save
+                        * the clone flags for deciding how to linking
+                        * up the child and parent processes.
+                        * CHECK: Do we need to call get_arg0?  The
+                        * old version of the clone/clone2 code down below
+                        * just read tcp->u_arg[arg0_index] without
+                        * calling get_arg0.  Was that a bug?
+                        */
+                       if (arg_setup (tcp, &state) < 0
+                           || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
+                           || get_arg1 (tcp, &state, &tcp->inst[1]) < 0)
+                               return -1;
+                       tcp->u_arg[arg0_index] = tcp->inst[0];
+                       return 0;
+               }
+       }
+#  endif /* PTRACE_EVENT_FORK */
+
        if (arg_setup (tcp, &state) < 0
            || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
            || get_arg1 (tcp, &state, &tcp->inst[1]) < 0)
-- 
1.7.0.4

_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to