On Tue, 2008-12-16 at 21:25 +0100, Denys Vlasenko wrote:
> 2008-12-16  Denys Vlasenko  <dvlas...@redhat.com>
> 
>       * defs.h: Add new field "sigtrap80" to struct tcb.
>       * strace.c (alloc_tcb): Initialize it.
>       (detach, trace): Use it in place of constant SIGTRAP.
>       (trace): Set PTRACE_O_TRACESYSGOOD and PTRACE_O_TRACEEXEC
>       options on newly traced threads; detect these
>       options if they are inherited across clone(); detect
>       and handle execve's ptrace stop; add paranoia checks
>       if real SIGTRAP is seen.

Now even with patch! :)


diff -d -urpN strace.2/defs.h strace.3/defs.h
--- strace.2/defs.h     2008-12-16 19:06:33.000000000 +0100
+++ strace.3/defs.h     2008-12-16 21:09:09.000000000 +0100
@@ -322,8 +322,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 -d -urpN strace.2/strace.c strace.3/strace.c
--- strace.2/strace.c   2008-12-16 19:06:33.000000000 +0100
+++ strace.3/strace.c   2008-12-16 21:06:59.000000000 +0100
@@ -943,6 +943,7 @@ alloc_tcb(int pid, int command_options_p
                        tcp->nclone_waiting = 0;
 #endif
                        tcp->flags = TCB_INUSE | TCB_STARTUP;
+                       tcp->sigtrap80 = SIGTRAP;
                        tcp->outf = outf; /* Initialise to current out file */
                        tcp->stime.tv_sec = 0;
                        tcp->stime.tv_usec = 0;
@@ -1555,9 +1556,9 @@ int sig;
                                }
                                break;
                        }
-                       if ((error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
-                           WSTOPSIG(status) == SIGTRAP ?
-                           0 : WSTOPSIG(status))) < 0) {
+                       error = ptrace(PTRACE_CONT, tcp->pid, (char *) 1,
+                               WSTOPSIG(status) == tcp->sigtrap80 ? 0 : 
WSTOPSIG(status));
+                       if (error < 0) {
                                if (errno != ESRCH)
                                        perror("detach: ptrace(PTRACE_CONT, 
...)");
                                break;
@@ -2418,10 +2419,75 @@ Process %d attached (waiting for parent)
                                        return -1;
                                }
                        }
+                       /*
+                        * 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) {
+//fprintf(stderr, "ptrace(PTRACE_SETOPTIONS, ..., 
PTRACE_O_TRACESYSGOOD|PTRACE_O_TRACEEXEC) successful\n");
+                               tcp->sigtrap80 = SIGTRAP | 0x80;
+                       }
                        goto tracing;
                }
 
-               if (WSTOPSIG(status) != SIGTRAP) {
+               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.  */
+//fprintf(stderr, "got PTRACE_EVENT_EXEC, setting %x -> %x\n", status, status 
| 0x8000);
+                               /* 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);
+               }
+
+               if (WSTOPSIG(status) != tcp->sigtrap80) {
+                       /* This isn't a ptrace stop.  */
+
                        if (WSTOPSIG(status) == SIGSTOP &&
                                        (tcp->flags & TCB_SIGTRAPPED)) {
                                /*



------------------------------------------------------------------------------
SF.Net email is Sponsored by MIX09, March 18-20, 2009 in Las Vegas, Nevada.
The future of the web can't happen without you.  Join us at MIX09 to help
pave the way to the Next Web now. Learn more and register at
http://ad.doubleclick.net/clk;208669438;13503038;i?http://2009.visitmix.com/
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to