[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