* strace.c [LINUX && PTRACE_EVENT_FORK] (trace): Handle Linux
PTRACE_EVENT_{FORK,VFORK,CLONE} events.  If one signals that a
fork/vfork/clone happened, begin tracing the child process immediately
without waiting for the parent syscall to return.  Set TCB_FORK_EVENT
so the syscall return doesn't try to attach to the child.

Signed-off-by: Jamie Lokier <ja...@shareable.org>
---
 process.c |    5 ++---
 strace.c  |   35 +++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/process.c b/process.c
index e46957d..bfc4c9d 100644
--- a/process.c
+++ b/process.c
@@ -790,9 +790,8 @@ change_syscall(struct tcb *tcp, int new)
 #ifdef LINUX
 /*
  * Called when we learn about a child process and know which parent
- * it's from.  (Dubiously, pid here is int
- * because alloctcb() uses it, but syscall return values are unsigned
- * long and could overflow.)
+ * it's from.  (Dubiously, pid here is int because alloctcb() uses it,
+ * but syscall return values are unsigned long and could overflow.)
  *
  * from_ptrace_event is set if called for PTRACE_EVENT_{FORK,VFORK,CLONE}.
  * Then we know the child is attached and tracing despite CLONE_PTRACE
diff --git a/strace.c b/strace.c
index 5b44f1c..ac807f0 100644
--- a/strace.c
+++ b/strace.c
@@ -2580,6 +2580,41 @@ Process %d attached (waiting for parent)\n",
                        tcp->flags &= ~TCB_SUSPENDED;
                        continue;
                }
+
+#if defined LINUX && defined PTRACE_EVENT_FORK
+               /*
+                * When there is a PTRACE_EVENT_*, WSTOPSIG(status) == SIGTRAP
+                * because that macro ignores the upper 16 bits, at least on
+                * Linux where these events occur.
+                *
+                * These events don't replace syscall entry and exit.
+                * They are additional events, in the middle.
+                */
+               if ((status >> 16) != 0) {
+                       /* PTRACE_GETEVENTMSG takes pointer to unsigned long.*/
+                       unsigned long child = 0;
+                       if (followfork
+                           /* FIXME: Should check it's a fork syscall. */
+                           && (tcp->flags & TCB_INSYSCALL)
+                           && ((status >> 16) == PTRACE_EVENT_FORK
+                               || (status >> 16) == PTRACE_EVENT_VFORK
+                               || (status >> 16) == PTRACE_EVENT_CLONE)
+                           && ptrace(PTRACE_GETEVENTMSG, tcp->pid,
+                                     (char *) 1, (long) &child) == 0
+                           && (int)child > 0 && (unsigned int)child == child) {
+                               if (internal_fork_child(tcp, child, 1) < 0) {
+                                       cleanup();
+                                       return -1;
+                               }
+                               tcp->flags |= TCB_FORK_EVENT;
+                       } else {
+                               fprintf(stderr, "pid %d stray PTRACE_EVENT\n",
+                                       tcp->pid);
+                       }
+                       goto tracing;
+               }
+#endif /* LINUX && PTRACE_EVENT_FORK */
+
                /* we handled the STATUS, we are permitted to interrupt now. */
                if (interrupted)
                        return 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