[PATCH/v3 1/2] Test how PTRACE_SETOPTIONS support works
Wang Chao
wang.chao at cn.fujitsu.com
Fri Nov 12 09:25:19 UTC 2010
Currently only test fork related options. Fork a child that uses
PTRACE_TRACEME at startup and then does a fork so strace can test
how the PTRACE_SETOPTIONS support works before it handles any real
tracee. Since PTRACE_O_TRACECLONE/*FORK were introduced to kernel
at the same time, so this test seems enough for these 3 options.
* defs.h [LINUX]: Define PTRACE_O_TRACECLONE et al macros here;
Variable declaration.
* strace.c [LINUX](test_ptrace_setoptions): New function for testing
whether kernel supports PTRACE_O_CLONE/*FORK, the result is stored
in the new variable for later use.
(main): Call that function if followfork option is set.
Signed-off-by: Wang Chao <wang.chao at cn.fujitsu.com>
---
defs.h | 26 ++++++++++++++++++++
strace.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 107 insertions(+), 0 deletions(-)
diff --git a/defs.h b/defs.h
index fc7e362..eee4710 100644
--- a/defs.h
+++ b/defs.h
@@ -308,6 +308,31 @@ extern int mp_ioctl (int f, int c, void *a, int s);
#define PR_FAULTED S_CORE
#endif
+#ifdef LINUX
+# ifndef PTRACE_SETOPTIONS
+# define PTRACE_SETOPTIONS 0x4200
+# endif
+# ifndef PTRACE_O_TRACEFORK
+# define PTRACE_O_TRACEFORK 0x00000002
+# endif
+# ifndef PTRACE_O_TRACEVFORK
+# define PTRACE_O_TRACEVFORK 0x00000004
+# endif
+# ifndef PTRACE_O_TRACECLONE
+# define PTRACE_O_TRACECLONE 0x00000008
+# endif
+
+# ifndef PTRACE_EVENT_FORK
+# define PTRACE_EVENT_FORK 1
+# endif
+# ifndef PTRACE_EVENT_VFORK
+# define PTRACE_EVENT_VFORK 2
+# endif
+# ifndef PTRACE_EVENT_CLONE
+# define PTRACE_EVENT_CLONE 3
+# endif
+#endif /* LINUX */
+
/* Trace Control Block */
struct tcb {
short flags; /* See below for TCB_ values */
@@ -470,6 +495,7 @@ typedef enum {
extern struct tcb **tcbtab;
extern int *qual_flags;
extern int debug, followfork;
+extern unsigned int ptrace_setoptions;
extern int dtime, xflag, qflag;
extern cflag_t cflag;
extern int acolumn;
diff --git a/strace.c b/strace.c
index 497b8d1..09aedac 100644
--- a/strace.c
+++ b/strace.c
@@ -83,6 +83,7 @@ extern char *optarg;
int debug = 0, followfork = 0;
+unsigned int ptrace_setoptions = 0;
int dtime = 0, xflag = 0, qflag = 0;
cflag_t cflag = CFLAG_NONE;
static int iflag = 0, interactive = 0, pflag_seen = 0, rflag = 0, tflag = 0;
@@ -686,6 +687,77 @@ startup_child (char **argv)
#endif /* USE_PROCFS */
}
+#ifdef LINUX
+/*
+ * Test whether kernel support PTRACE_O_TRACECLONE et al options.
+ * First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
+ * and then see which options are supported on this kernel.
+ */
+static int
+test_ptrace_setoptions(void)
+{
+ int pid;
+
+ if ((pid = fork()) < 0)
+ return -1;
+ else if (pid == 0) {
+ if (ptrace(PTRACE_TRACEME, 0, (char *)1, 0) < 0) {
+ _exit(1);
+ }
+ kill(getpid(), SIGSTOP);
+ if ((pid = fork()) < 0) {
+ _exit(1);
+ }
+ _exit(0);
+ }
+ else {
+ int status, tracee_pid, error;
+ int no_child = 0;
+ while (1) {
+ tracee_pid = wait4(-1, &status, 0, NULL);
+ error = errno;
+ if (tracee_pid == -1) {
+ switch (error) {
+ case EINTR:
+ continue;
+ case ECHILD:
+ no_child = 1;
+ break;
+ default:
+ errno = error;
+ perror("test_ptrace_setoptions");
+ return -1;
+ }
+ }
+ if (no_child)
+ break;
+ if (tracee_pid != pid) {
+ if (ptrace(PTRACE_CONT, tracee_pid, 0, 0) < 0 &&
+ errno != ESRCH)
+ kill(tracee_pid, SIGKILL);
+ }
+ else if (WIFSTOPPED(status)) {
+ if (status >> 16 == PTRACE_EVENT_FORK)
+ ptrace_setoptions |= (PTRACE_O_TRACEVFORK |
+ PTRACE_O_TRACECLONE |
+ PTRACE_O_TRACEFORK);
+ if (WSTOPSIG(status) == SIGSTOP) {
+ if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
+ PTRACE_O_TRACEFORK) < 0) {
+ kill(pid, SIGKILL);
+ return -1;
+ }
+ }
+ if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0 &&
+ errno != ESRCH)
+ kill(pid, SIGKILL);
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
int
main(int argc, char *argv[])
{
@@ -914,6 +986,15 @@ main(int argc, char *argv[])
interactive = 0;
qflag = 1;
}
+
+#ifdef LINUX
+ if (followfork && test_ptrace_setoptions() < 0) {
+ fprintf(stderr, "Test for options supported by PTRACE_SETOPTIONS\
+ failed, give up using this feature\n");
+ ptrace_setoptions = 0;
+ }
+#endif
+
/* Valid states here:
optind < argc pflag_seen outfname interactive
1 0 0 1
--
1.6.5.2
More information about the Strace-devel
mailing list