[PATCH 2/2] Trace fork series calls using PTRACE_SETOPTIONS on linux
Wang Chao
wang.chao at cn.fujitsu.com
Wed Sep 1 09:17:56 UTC 2010
* defs.h: Variable declaration.
* process.c (internal_fork): Do nothing if using PTRACE_SETOPTIONS
to trace fork series calls.
* strace.c (trace): Set ptrace options and handle trap with flag
PTRACE_EVENT_{CLONE,VFORK,FORK}.
Signed-off-by: Wang Chao <wang.chao at cn.fujitsu.com>
---
defs.h | 1 +
process.c | 5 ++++-
strace.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+), 1 deletions(-)
diff --git a/defs.h b/defs.h
index a813f5b..3642fce 100644
--- a/defs.h
+++ b/defs.h
@@ -470,6 +470,7 @@ typedef enum {
extern struct tcb **tcbtab;
extern int *qual_flags;
extern int debug, followfork;
+extern int ptrace_setoptions;
extern int dtime, xflag, qflag;
extern cflag_t cflag;
extern int acolumn;
diff --git a/process.c b/process.c
index 7f9353a..9365495 100644
--- a/process.c
+++ b/process.c
@@ -837,13 +837,16 @@ internal_fork(struct tcb *tcp)
if (!followfork)
return 0;
fork_tcb(tcp);
- if (setbpt(tcp) < 0)
+ if (ptrace_setoptions || setbpt(tcp) < 0)
return 0;
} else {
struct tcb *tcpchild;
int pid;
int bpt;
+ if (ptrace_setoptions)
+ return 0;
+
if (!(tcp->flags & TCB_FOLLOWFORK))
return 0;
diff --git a/strace.c b/strace.c
index c1d6539..70b9222 100644
--- a/strace.c
+++ b/strace.c
@@ -82,6 +82,8 @@ extern int optind;
extern char *optarg;
+/* use PTRACE_SETOPTIONS to trace fork series calls. */
+int ptrace_setoptions = 0;
int debug = 0, followfork = 0;
int dtime = 0, xflag = 0, qflag = 0;
cflag_t cflag = CFLAG_NONE;
@@ -2454,6 +2456,51 @@ Process %d attached (waiting for parent)\n",
fprintf(stderr, "pid %u stopped, [%s]\n",
pid, signame(WSTOPSIG(status)));
+ if (ptrace_setoptions &&
+ (status >> 16 == PTRACE_EVENT_VFORK ||
+ status >> 16 == PTRACE_EVENT_CLONE ||
+ status >> 16 == PTRACE_EVENT_FORK)) {
+ struct tcb *tcpchild = NULL;
+ int childpid;
+
+ ptrace(PTRACE_GETEVENTMSG, 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);
+ goto tracing;
+ }
+
+ 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
+ goto tracing;
+ }
+
/*
* Interestingly, the process may stop
* with STOPSIG equal to some other signal
@@ -2481,6 +2528,12 @@ Process %d attached (waiting for parent)\n",
return -1;
}
}
+#ifdef LINUX
+ if (followfork && tcp->parent == NULL &&
+ ptrace(PTRACE_SETOPTIONS, tcp->pid, NULL,
+ PTRACE_O_TRACEFORK|PTRACE_O_TRACEVFORK|PTRACE_O_TRACECLONE) == 0)
+ ptrace_setoptions = 1;
+#endif
goto tracing;
}
--
1.6.5.2
More information about the Strace-devel
mailing list