If PTRACE_O_TRACECLONE et al options are supported by kernel, we use them to do followfork rather than the original setbpt method which change registers ourselves.
* process.c [LINUX](internal_fork): Do nothing if these options are supported by kernel. [LINUX](reparent): Need not to do reparent for *fork syscalls. * strace.c [LINUX](handle_ptrace_event): New function. [LINUX](trace): If ptrace_setoptions is in effect: 1) Call the new function to handle PTRACE_EVENT_* status. 2) Set PTRACE_SETOPTIONS when we see the initial stop of tracee. Signed-off-by: Wang Chao <[email protected]> --- process.c | 7 ++++++ strace.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 0 deletions(-) diff --git a/process.c b/process.c index 3cf6d28..740d66f 100644 --- a/process.c +++ b/process.c @@ -794,6 +794,8 @@ change_syscall(struct tcb *tcp, int new) #ifdef LINUX void reparent(struct tcb *tcp, struct tcb *tcpchild) { + if (sysent[tcp->scno].sys_func != sys_clone) + return; /* * Save the flags used in this call, * in case we point TCP to our parent below. @@ -835,6 +837,11 @@ void reparent(struct tcb *tcp, struct tcb *tcpchild) int internal_fork(struct tcb *tcp) { + if ((ptrace_setoptions + & (PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK)) + == (PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK)) + return 0; + if (entering(tcp)) { if (!followfork) return 0; diff --git a/strace.c b/strace.c index e694f17..299fb55 100644 --- a/strace.c +++ b/strace.c @@ -2356,6 +2356,56 @@ handle_group_exit(struct tcb *tcp, int sig) } #endif +#ifdef LINUX +int handle_ptrace_event(int status, struct tcb *tcp) +{ + if (status >> 16 == PTRACE_EVENT_VFORK || + status >> 16 == PTRACE_EVENT_CLONE || + status >> 16 == PTRACE_EVENT_FORK) { + struct tcb *tcpchild = NULL; + int childpid; + + ptrace(PTRACE_GETEVENTMSG, tcp->pid, NULL, &childpid); + tcpchild = pid2tcb(childpid); + if (tcpchild == NULL) { + tcpchild = alloctcb(childpid); + } + else if ((tcpchild->flags + & (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED)) + != (TCB_STARTUP|TCB_ATTACHED|TCB_SUSPENDED)) + fprintf(stderr, + "[preattached child %d of %d in weird state!]\n", + childpid, tcp->pid); + + tcpchild->flags |= TCB_ATTACHED; + if (tcpchild->flags & TCB_SUSPENDED) { + tcpchild->flags &= ~TCB_SUSPENDED; + if (ptrace_restart(PTRACE_SYSCALL, tcpchild, 0) < 0) { + fprintf(stderr, "Restart suspended child %d with error\n", + tcpchild->pid); + return 1; + } + + if (!qflag) + fprintf(stderr, + "Process %u resumed (parent %d ready)\n", + childpid, tcp->pid); + } + else { + if (!qflag) + fprintf(stderr, "Process %d attached\n", childpid); + } + tcpchild->parent = tcp; + ++tcp->nchildren; +#ifdef TCB_CLONE_THREAD + reparent(tcp, tcpchild); +#endif + return 1; + } + return 0; +} +#endif + static int trace() { @@ -2541,6 +2591,11 @@ Process %d attached (waiting for parent)\n", fprintf(stderr, "pid %u stopped, [%s]\n", pid, signame(WSTOPSIG(status))); + if (ptrace_setoptions && (status >> 16)) { + if (handle_ptrace_event(status, tcp)) + goto tracing; + } + /* * Interestingly, the process may stop * with STOPSIG equal to some other signal @@ -2568,6 +2623,13 @@ Process %d attached (waiting for parent)\n", return -1; } } +#ifdef LINUX + if (followfork && (tcp->parent == NULL) && ptrace_setoptions) + if (ptrace(PTRACE_SETOPTIONS, tcp->pid, + NULL, ptrace_setoptions) < 0) + /* should not happen. */ + ptrace_setoptions = 0; +#endif goto tracing; } -- 1.6.5.2 ------------------------------------------------------------------------------ Start uncovering the many advantages of virtual appliances and start using them to simplify application deployment and accelerate your shift to cloud computing. http://p.sf.net/sfu/novell-sfdev2dev _______________________________________________ Strace-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/strace-devel
