>From 15a8755d7a53dbd035b914b8fb0eeafe6ba9dcd2 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <[email protected]>
Date: Mon, 22 Dec 2008 19:14:47 +0000
Subject: [PATCH] Make strace correctly handle SIGTRAP produced by e.g.
 kill(2) and by trapping instruction.

* defs.h: Add sigtrap80 field to struct tcb.
* strace.c (alloc_tcb): Initialize it to SIGTRAP.
(detach): Use tcp->sigtrap80 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".
---
 defs.h   |    4 ++-
 strace.c |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/defs.h b/defs.h
index 5bcaa07..1694e0b 100644
--- a/defs.h
+++ b/defs.h
@@ -335,8 +335,10 @@ struct tcb {
        int nclone_threads;     /* # of nchildren with CLONE_THREAD */
        int nclone_detached;    /* # of nchildren with CLONE_DETACHED */
        int nclone_waiting;     /* clone threads in wait4 (TCB_SUSPENDED) */
-#endif
                                /* (1st arg of wait4()) */
+#endif
+       int sigtrap80;          /* What sig we consider to be ptrace stop */
+                               /* (can be SIGTRAP or (SIGTRAP|0x80) only) */
        long baddr;             /* `Breakpoint' address */
        long inst[2];           /* Instructions on above */
        int pfd;                /* proc file descriptor */
diff --git a/strace.c b/strace.c
index 7294e8e..ecbac78 100644
--- a/strace.c
+++ b/strace.c
@@ -1016,6 +1016,7 @@ alloc_tcb(int pid, int command_options_parsed)
                        tcp->nclone_waiting = 0;
 #endif
                        tcp->flags = TCB_INUSE | TCB_STARTUP;
+                       tcp->sigtrap80 = SIGTRAP;
                        tcp->outf = outf; /* Initialise to current out file */
                        tcp->curcol = 0;
                        tcp->stime.tv_sec = 0;
@@ -1622,7 +1623,7 @@ int sig;
                                break;
                        }
                        error = ptrace_restart(PTRACE_CONT, tcp,
-                                       WSTOPSIG(status) == SIGTRAP ? 0
+                                       WSTOPSIG(status) == tcp->sigtrap80 ? 0
                                        : WSTOPSIG(status));
                        if (error < 0)
                                break;
@@ -2484,10 +2485,77 @@ Process %d attached (waiting for parent)\n",
                                        return -1;
                                }
                        }
+#ifdef LINUX /* add more OSes after you verified it works for them */
+                       /*
+                        * Ask kernel to set signo to SIGTRAP | 0x80
+                        * on ptrace-generated SIGTRAPs, and mark
+                        * execve's SIGTRAP with PTRACE_EVENT_EXEC.
+                        */
+                       if (tcp->sigtrap80 == SIGTRAP
+                        && ptrace(PTRACE_SETOPTIONS, pid, (char *) 0,
+                                       (void *) (PTRACE_O_TRACESYSGOOD | 
PTRACE_O_TRACEEXEC)) == 0) {
+                               tcp->sigtrap80 = SIGTRAP | 0x80;
+                       }
+#endif
                        goto tracing;
                }
 
-               if (WSTOPSIG(status) != SIGTRAP) {
+#ifdef LINUX
+               if (tcp->sigtrap80 != 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_errno:0              si_errno:(?)
+                                * si_code:128 (SI_KERNEL) si_code:0 (SI_USER)
+                                * si_pid:0                si_pid:(>0?)
+                                * si_band:0               si_band:(?)
+                                * 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 it's ptrace stop\n", si.si_code);
+                                       /* Set WSTOPSIG(status) = (SIGTRAP | 
0x80).  */
+                                       status |= 0x8000;
+                               }
+                       }
+               }
+
+               if (WSTOPSIG(status) == (SIGTRAP | 0x80)
+                /* && tcp->sigtrap80 == SIGTRAP - redundant */
+               ) {
+                       /*
+                        * If tcp->sigtrap80 == SIGTRAP but we got it
+                        * ORed with 0x80, it's a CLONE_PTRACEd child
+                        * which inherited "SIGTRAP | 0x80" setting.
+                        * Whee. Just record this remarkable fact.
+                        */
+                       tcp->sigtrap80 = (SIGTRAP | 0x80);
+               }
+#endif
+
+               if (WSTOPSIG(status) != tcp->sigtrap80) {
+                       /* This isn't a ptrace stop.  */
+
                        if (WSTOPSIG(status) == SIGSTOP &&
                                        (tcp->flags & TCB_SIGTRAPPED)) {
                                /*
-- 
1.6.5.1


Andreas.

-- 
Andreas Schwab, [email protected]
GPG Key fingerprint = D4E8 DBE3 3813 BB5D FA84  5EC7 45C6 250E 6F00 984E
"And now for something completely different."

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Strace-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to