* 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