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

Reply via email to