[PATCH] Try to use PTRACE_SETOPTIONS to handle non-ptrace SIGTRAP
Andreas Schwab
schwab at redhat.com
Wed Feb 24 12:44:38 UTC 2010
* defs.h (use_ptrace_setoptions): Declare.
* strace.c (set_ptrace_options): Define.
(is_ptrace_stop): Define.
(is_post_execve_trap): Define.
(trace): Use them.
* process.c (internal_exec): Don't set TCB_WAITEXECVE if
PTRACE_SETOPTIONS works.
---
defs.h | 16 +++++++++++++
process.c | 5 ++++
strace.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 92 insertions(+), 1 deletions(-)
diff --git a/defs.h b/defs.h
index 4797e96..c0d2dcc 100644
--- a/defs.h
+++ b/defs.h
@@ -246,6 +246,22 @@ extern int ptrace(int, int, char *, int, ...);
#define PERSONALITY1_WORDSIZE 4
#endif
+#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
+# define USE_PTRACE_SETOPTIONS
+# ifndef PTRACE_O_TRACESYSGOOD
+# define PTRACE_O_TRACESYSGOOD 0x00000001
+# endif
+# ifndef PTRACE_O_TRACEEXEC
+# define PTRACE_O_TRACEEXEC 0x00000010
+# endif
+# ifndef PTRACE_EVENT_EXEC
+# define PTRACE_EVENT_EXEC 4
+# endif
+extern int use_ptrace_setoptions;
+#else
+# define use_ptrace_setoptions 0
+#endif
+
#ifdef SVR4
#ifdef HAVE_MP_PROCFS
extern int mp_ioctl (int f, int c, void *a, int s);
diff --git a/process.c b/process.c
index c69e45e..eb464e2 100644
--- a/process.c
+++ b/process.c
@@ -1732,6 +1732,11 @@ struct tcb *tcp;
fixvfork(tcp);
#endif /* SUNOS4 */
#if defined LINUX && defined TCB_WAITEXECVE
+#ifdef USE_PTRACE_SETOPTIONS
+ /* Don't set TCB_WAITEXECVE when PTRACE_SETOPTIONS works. */
+ if (use_ptrace_setoptions > 0)
+ return 0;
+#endif
if (exiting(tcp) && syserror(tcp))
tcp->flags &= ~TCB_WAITEXECVE;
else
diff --git a/strace.c b/strace.c
index 2fb75c9..bb29729 100644
--- a/strace.c
+++ b/strace.c
@@ -2253,6 +2253,72 @@ handle_group_exit(struct tcb *tcp, int sig)
}
#endif
+#ifdef USE_PTRACE_SETOPTIONS
+int use_ptrace_setoptions = -1;
+
+static void
+set_ptrace_options(struct tcb *tcp)
+{
+ /*
+ * Ask kernel to set signo to SIGTRAP | 0x80
+ * on ptrace-generated SIGTRAPs, and mark
+ * execve's SIGTRAP with PTRACE_EVENT_EXEC.
+ */
+ if (use_ptrace_setoptions)
+ if (ptrace(PTRACE_SETOPTIONS, tcp->pid, (char *) 0,
+ (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC)) < 0)
+ use_ptrace_setoptions = 0;
+}
+
+static int
+is_ptrace_stop(struct tcb *tcp, int status)
+{
+ if (!use_ptrace_setoptions)
+ return WSTOPSIG(status) == SIGTRAP;
+ if (use_ptrace_setoptions > 0)
+ return (WSTOPSIG(status) == (SIGTRAP | 0x80) ||
+ ((unsigned)status >> 16) == PTRACE_EVENT_EXEC);
+
+ /* Check whether PTRACE_SETOPTIONS works. */
+ if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
+ /* PTRACE_O_TRACESYSGOOD works. */
+ use_ptrace_setoptions = 1;
+ return 1;
+ }
+ if (WSTOPSIG(status) == SIGTRAP) {
+ siginfo_t si;
+
+ /* Check for post-execve trap. */
+ if (((unsigned)status >> 16) == PTRACE_EVENT_EXEC) {
+ /* PTRACE_O_TRACEEXEC works. */
+ use_ptrace_setoptions = 1;
+ return 1;
+ }
+ if (ptrace(PTRACE_GETSIGINFO, tcp->pid, (void *)0,
+ (long)&si) == 0 &&
+ (tprintf("[si_signo = %d, si_code = %d]\n",
+ si.si_signo, si.si_code),
+ (si.si_signo != SIGTRAP ||
+ (si.si_code != SI_KERNEL && si.si_code != SI_USER))))
+ /* PTRACE_O_TRACEEXEC does not work. */
+ use_ptrace_setoptions = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+is_post_execve_trap(struct tcb *tcp, int status)
+{
+ return (use_ptrace_setoptions && WSTOPSIG(status) == SIGTRAP &&
+ ((unsigned)status >> 16) == PTRACE_EVENT_EXEC);
+}
+#else
+#define set_ptrace_options(tcp)
+#define is_ptrace_stop(tcp, status) (WSTOPSIG(status) == SIGTRAP)
+#define is_post_execve_trap(tcp, status) 0
+#endif
+
static int
trace()
{
@@ -2465,10 +2531,11 @@ Process %d attached (waiting for parent)\n",
return -1;
}
}
+ set_ptrace_options(tcp);
goto tracing;
}
- if (WSTOPSIG(status) != SIGTRAP) {
+ if (!is_ptrace_stop(tcp, status)) {
if (WSTOPSIG(status) == SIGSTOP &&
(tcp->flags & TCB_SIGTRAPPED)) {
/*
@@ -2530,6 +2597,9 @@ Process %d attached (waiting for parent)\n",
tcp->flags &= ~TCB_SUSPENDED;
continue;
}
+ /* Ignore post-execve trap. */
+ if (is_post_execve_trap(tcp, status))
+ goto tracing;
/* we handled the STATUS, we are permitted to interrupt now. */
if (interrupted)
return 0;
--
1.7.0
--
Andreas Schwab, schwab at redhat.com
GPG Key fingerprint = D4E8 DBE3 3813 BB5D FA84 5EC7 45C6 250E 6F00 984E
"And now for something completely different."
More information about the Strace-devel
mailing list