[PATCH] Make strace correctly handle SIGTRAP produced by e.g. kill(2) and by trapping instruction.
Andreas Schwab
schwab at redhat.com
Mon Dec 14 16:54:17 UTC 2009
>From f441134f7e5782a23f94cd38b941de1472a6577b Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <dvlasenk at redhat.com>
Date: Tue, 13 Jan 2009 18:30:55 +0000
Subject: [PATCH] Make strace correctly handle SIGTRAP produced by e.g.
kill(2) and by trapping instruction.
* strace.c (ptrace_stop_sig): Define.
(detach): Use it instead of SIGTRAP constant.
(trace): Attempt to set PTRACE_O_TRACESYSGOOD and
PTRACE_O_TRACEEXEC options on each newly attached process,
distinquish between SIGTRAP and (SIGTRAP | 0x80) stops.
Fixes RH#162774 "strace ignores int3 SIGTRAP".
---
strace.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 74 insertions(+), 2 deletions(-)
diff --git a/strace.c b/strace.c
index d236516..bf8b1c0 100644
--- a/strace.c
+++ b/strace.c
@@ -104,6 +104,8 @@ int not_failing_only = 0;
static int exit_code = 0;
static int strace_child = 0;
+static int ptrace_stop_sig = SIGTRAP;
+static bool ptrace_opts_set;
static char *username = NULL;
uid_t run_uid;
@@ -1618,7 +1620,7 @@ int sig;
break;
}
error = ptrace_restart(PTRACE_CONT, tcp,
- WSTOPSIG(status) == SIGTRAP ? 0
+ WSTOPSIG(status) == ptrace_stop_sig ? 0
: WSTOPSIG(status));
if (error < 0)
break;
@@ -2480,10 +2482,80 @@ Process %d attached (waiting for parent)\n",
return -1;
}
}
+/* Add more OSes after you verified it works for them. */
+/* PTRACE_SETOPTIONS may be an enum, not a #define.
+ * But sometimes we can test for it by checking PT_SETOPTIONS.
+ */
+#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_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
+ /*
+ * Ask kernel to set signo to SIGTRAP | 0x80
+ * on ptrace-generated SIGTRAPs, and mark
+ * execve's SIGTRAP with PTRACE_EVENT_EXEC.
+ */
+ if (!ptrace_opts_set) {
+ ptrace_opts_set = 1;
+ /*
+ * NB: even if this "succeeds", we can
+ * revert back to SIGTRAP if we later see
+ * that it didnt really work.
+ * Old kernels are known to lie here.
+ */
+ if (ptrace(PTRACE_SETOPTIONS, pid, (char *) 0,
+ (void *) (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC)) == 0)
+ ptrace_stop_sig = SIGTRAP | 0x80;
+ }
+#endif
goto tracing;
}
- if (WSTOPSIG(status) != SIGTRAP) {
+#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
+ if (ptrace_stop_sig != SIGTRAP && WSTOPSIG(status) == SIGTRAP) {
+ /*
+ * We told ptrace to report SIGTRAP | 0x80 on this process
+ * but got bare SIGTRAP. This can be a genuine SIGTRAP:
+ * kill(pid, SIGTRAP), trap insn, etc;
+ * but be paranoid about it.
+ */
+ if (((unsigned)status >> 16) == PTRACE_EVENT_EXEC) {
+ /* It's post-exec ptrace stop. */
+ /* Set WSTOPSIG(status) = (SIGTRAP | 0x80). */
+ status |= 0x8000;
+ } else {
+ /* Take a better look... */
+ siginfo_t si;
+ ptrace(PTRACE_GETSIGINFO, pid, (void*) 0, (void*) &si);
+ /*
+ * Check some fields to make sure we see
+ * real SIGTRAP.
+ * Otherwise interpret it as ptrace stop.
+ * Real SIGTRAPs (int3 insn on x86, kill() etc)
+ * have these values:
+ * int3: kill -TRAP $pid:
+ * si_signo:5 (SIGTRAP) si_signo:5 (SIGTRAP)
+ * si_code:128 (SI_KERNEL) si_code:0 (SI_USER)
+ * Ptrace stops have garbage there instead.
+ */
+ if (si.si_signo != SIGTRAP
+ || (si.si_code != SI_KERNEL && si.si_code != SI_USER)) {
+ fprintf(stderr, "bogus SIGTRAP (si_code:%x), assuming old kernel\n", si.si_code);
+ ptrace_stop_sig = SIGTRAP;
+ }
+ }
+ }
+#endif
+
+ if (WSTOPSIG(status) != ptrace_stop_sig) {
+ /* This isn't a ptrace stop. */
+
if (WSTOPSIG(status) == SIGSTOP &&
(tcp->flags & TCB_SIGTRAPPED)) {
/*
--
1.6.5.5
Andreas.
--
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