[PATCH 2/3] Test how PTRACE_SETOPTIONS support works

Wang Chao wang.chao at cn.fujitsu.com
Thu Sep 16 08:35:05 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.

Signed-off-by: Wang Chao <wang.chao at cn.fujitsu.com>
---
 defs.h   |   16 +++++++++++++
 strace.c |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+), 0 deletions(-)

diff --git a/defs.h b/defs.h
index 0b3ba43..daed8c6 100644
--- a/defs.h
+++ b/defs.h
@@ -308,6 +308,21 @@ 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
+#endif /* LINUX */
+
 /* Trace Control Block */
 struct tcb {
 	short flags;		/* See below for TCB_ values */
@@ -470,6 +485,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..e694f17 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,70 @@ 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.
+ */
+int test_ptrace_setoptions()
+{
+	int pid;
+	unsigned int test_options = PTRACE_O_TRACEFORK;
+
+	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, wait_errno;
+		int no_child = 0;
+		while(1) {
+			tracee_pid = wait4(-1, &status, 0, NULL);
+			wait_errno = errno;
+			if (tracee_pid == -1) {
+				switch (wait_errno) {
+				case EINTR:
+					continue;
+				case ECHILD:
+					no_child = 1;
+					break;
+				default:
+					errno = wait_errno;
+					perror("test_ptrace_setoptions");
+					return -1;
+				}
+			}
+			if (no_child)
+				break;
+			if (tracee_pid != pid)
+				ptrace(PTRACE_CONT, tracee_pid, 0, 0);
+			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, test_options) < 0) {
+						ptrace(PTRACE_CONT, pid, 0, 0);
+						continue;
+					}
+				ptrace(PTRACE_SYSCALL, pid, 0, 0);
+			}
+		}
+	}
+	return 0;
+}
+#endif
+
 int
 main(int argc, char *argv[])
 {
@@ -914,6 +979,15 @@ main(int argc, char *argv[])
 		interactive = 0;
 		qflag = 1;
 	}
+
+#ifdef LINUX
+	if (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