]> granicus.if.org Git - strace/commitdiff
Set PTRACE_O_TRACEEXIT option and handle PTRACE_EVENT_EXIT events
authorDmitry V. Levin <ldv@altlinux.org>
Sat, 26 Nov 2016 23:45:05 +0000 (23:45 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sun, 27 Nov 2016 14:22:58 +0000 (14:22 +0000)
Do not assume that some syscalls do not generate syscall-exit-stops.
When syscalls fail for any reason they may generate syscall-exit-stops.

The solution is to wait for an actual exit reported by PTRACE_EVENT_EXIT
and print the end of unfinished exiting syscall properly.

* exit.c: Remove.
* Makefile.am (strace_SOURCES): Remove exit.c.
* linux/dummy.h (sys_exit): Alias to printargs_d.
* strace.c (ptrace_setoptions): Add PTRACE_O_TRACEEXIT bit.
(print_event_exit): New function.
(trace): Use it in case of PTRACE_EVENT_EXIT.
* syscall.c (trace_syscall_entering): Remove special handling
of SEN_exit.

Makefile.am
exit.c [deleted file]
linux/dummy.h
strace.c
syscall.c

index 97276f124dddd4b88e69d9c0d8a1770758c760f5..80e80fcc6c1d499b28ba38ebd21395ea3dd4c350 100644 (file)
@@ -104,7 +104,6 @@ strace_SOURCES =    \
        evdev.c         \
        eventfd.c       \
        execve.c        \
-       exit.c          \
        fadvise.c       \
        fallocate.c     \
        fanotify.c      \
diff --git a/exit.c b/exit.c
deleted file mode 100644 (file)
index b10f90c..0000000
--- a/exit.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "defs.h"
-
-SYS_FUNC(exit)
-{
-       if (exiting(tcp)) {
-               error_msg("%s returned!", tcp->s_ent->sys_name);
-               return -1;
-       }
-       /* special case: we stop tracing this process, finish line now */
-       tprintf("%ld) ", tcp->u_arg[0]);
-       tabto();
-       tprints("= ?\n");
-       line_ended();
-       return 0;
-}
index 49dcf16a01c396ff49ff8ae8e7d1484ce4582028..4cb9ad465c947a481df5a067721d6c7aa38c55ec 100644 (file)
 #define        sys_alarm               printargs_u
 
 /* printargs_d does the right thing */
+#define        sys_exit                printargs_d
 #define        sys_getpgid             printargs_d
 #define        sys_getsid              printargs_d
 #define        sys_nice                printargs_d
index 95e9d1433054b36dba0ec37a54639c1c4defe76d..5e081ab4738d93ecafc2dce8af996cff99155d92 100644 (file)
--- a/strace.c
+++ b/strace.c
@@ -80,7 +80,8 @@ const unsigned int syscall_trap_sig = SIGTRAP | 0x80;
 
 cflag_t cflag = CFLAG_NONE;
 unsigned int followfork = 0;
-unsigned int ptrace_setoptions = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC;
+unsigned int ptrace_setoptions = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC
+                                | PTRACE_O_TRACEEXIT;
 unsigned int xflag = 0;
 bool debug_flag = 0;
 bool Tflag = 0;
@@ -2158,6 +2159,43 @@ startup_tcb(struct tcb *tcp)
        }
 }
 
+static void
+print_event_exit(struct tcb *tcp)
+{
+       if (entering(tcp) || filtered(tcp) || hide_log(tcp)
+           || cflag == CFLAG_ONLY_STATS) {
+               return;
+       }
+
+       if (followfork < 2 && printing_tcp && printing_tcp != tcp
+           && printing_tcp->curcol != 0) {
+               current_tcp = printing_tcp;
+               tprints(" <unfinished ...>\n");
+               fflush(printing_tcp->outf);
+               printing_tcp->curcol = 0;
+               current_tcp = tcp;
+       }
+
+       if ((followfork < 2 && printing_tcp != tcp)
+           || (tcp->flags & TCB_REPRINT)) {
+               tcp->flags &= ~TCB_REPRINT;
+               printleader(tcp);
+               tprintf("<... %s resumed>", tcp->s_ent->sys_name);
+       }
+
+       if (!(tcp->sys_func_rval & RVAL_DECODED)) {
+               /*
+                * The decoder has probably decided to print something
+                * on exiting syscall which is not going to happen.
+                */
+               tprints(" <unfinished ...>");
+       }
+       tprints(") ");
+       tabto();
+       tprints("= ?\n");
+       line_ended();
+}
+
 /* Returns true iff the main trace loop has to continue. */
 static bool
 trace(void)
@@ -2308,10 +2346,14 @@ trace(void)
 
        sig = WSTOPSIG(status);
 
-       if (event != 0) {
-               /* Ptrace event */
+       switch (event) {
+               case 0:
+                       break;
+               case PTRACE_EVENT_EXIT:
+                       print_event_exit(tcp);
+                       goto restart_tracee_with_sig_0;
 #if USE_SEIZE
-               if (event == PTRACE_EVENT_STOP) {
+               case PTRACE_EVENT_STOP:
                        /*
                         * PTRACE_INTERRUPT-stop or group-stop.
                         * PTRACE_INTERRUPT-stop has sig == SIGTRAP here.
@@ -2324,9 +2366,10 @@ trace(void)
                                        stopped = true;
                                        goto show_stopsig;
                        }
-               }
+                       /* fall through */
 #endif
-               goto restart_tracee_with_sig_0;
+               default:
+                       goto restart_tracee_with_sig_0;
        }
 
        /*
index e5ab44a54659384cb519d1e56eaf4641b5f2a769..12962e2caf5ed1eb013d00f20631d9ff536df555 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -1148,7 +1148,7 @@ trace_syscall_entering(struct tcb *tcp)
 
        printleader(tcp);
        tprintf("%s(", tcp->s_ent->sys_name);
-       if ((tcp->qual_flg & QUAL_RAW) && SEN_exit != tcp->s_ent->sen)
+       if (tcp->qual_flg & QUAL_RAW)
                res = printargs(tcp);
        else
                res = tcp->s_ent->sys_func(tcp);