stage_out.c:added strace_openmemstream(), drop_staged_out(),
            publish_staged_out().
defs.h:     added flags stage_out, failing only
            struct tcb: new members memf, memfptr, memfloc.
syscall.c:  print output depending on flags and outcome.
strace.c:   added option -Z and help, modified tprintf, tprints
            setting flag stage_output in main().
---
 Makefile.am  |   1 +
 configure.ac |   1 +
 defs.h       |  18 +++++++++
 stage_out.c  | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 strace.1     |  31 ++++-----------
 strace.c     | 107 +++++++++++++++++++++++++++++++++++++++++++++++++---
 syscall.c    |  18 +++++++++
 7 files changed, 268 insertions(+), 28 deletions(-)
 create mode 100644 stage_out.c

diff --git a/Makefile.am b/Makefile.am
index afc3dd2..4550ff2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -226,6 +226,7 @@ strace_SOURCES =    \
        sockaddr.c      \
        socketutils.c   \
        sram_alloc.c    \
+       stage_out.c     \
        stat.c          \
        stat.h          \
        stat64.c        \
diff --git a/configure.ac b/configure.ac
index 793d74e..5a4212a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -285,6 +285,7 @@ AC_CHECK_FUNCS(m4_normalize([
        strsignal
        sync_file_range
        utimensat
+    open_memstream
 ]))
 
 AC_CHECK_TYPES([sig_atomic_t, struct sigcontext],,, [#include <signal.h>])
diff --git a/defs.h b/defs.h
index 09c0a5f..0236746 100644
--- a/defs.h
+++ b/defs.h
@@ -2,6 +2,7 @@
  * Copyright (c) 1991, 1992 Paul Kranenburg <p...@cs.few.eur.nl>
  * Copyright (c) 1993 Branko Lankester <bra...@hacktic.nl>
  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <j...@world.std.com>
+ * Copyright (C) 2016-2017 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -219,6 +220,12 @@ struct tcb {
        int sys_func_rval;      /* Syscall entry parser's return value */
        int curcol;             /* Output column for this process */
        FILE *outf;             /* Output file for this process */
+#if HAVE_OPEN_MEMSTREAM
+       FILE *memf;             /* Staged output file for this process */
+       char *memfptr;
+       size_t memfloc; 
+#endif  /* if HAVE_OPEN_MEMSTREAM */
+
        const char *auxstr;     /* Auxiliary info from syscall (see RVAL_STR) */
        void *_priv_data;       /* Private data for syscall decoding functions 
*/
        void (*_free_priv_data)(void *); /* Callback for freeing priv_data */
@@ -363,6 +370,10 @@ extern bool iflag;
 extern bool count_wallclock;
 extern unsigned int qflag;
 extern bool not_failing_only;
+extern bool failing_only;
+#if HAVE_OPEN_MEMSTREAM
+extern bool stage_output;       /* allows dropping of failed/successful 
syscalls output */
+#endif  /* if HAVE_OPEN_MEMSTREAM */
 extern unsigned int show_fd_path;
 /* are we filtering traces based on paths? */
 extern const char **paths_selected;
@@ -736,6 +747,13 @@ extern void tabto(void);
 extern void tprintf(const char *fmt, ...) ATTRIBUTE_FORMAT((printf, 1, 2));
 extern void tprints(const char *str);
 
+/*
+ *  staging output for -z/-Z (not_failing_only/failing_only)
+ */
+extern FILE *strace_openmemstream(struct tcb *tcp);
+extern void drop_staged_out(struct tcb *tcp);
+extern void publish_staged_out(struct tcb *tcp);
+
 #if SUPPORTED_PERSONALITIES > 1
 extern void set_personality(int personality);
 extern unsigned current_personality;
diff --git a/stage_out.c b/stage_out.c
new file mode 100644
index 0000000..88af3b8
--- /dev/null
+++ b/stage_out.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2016-2017 Intel Deutschland GmbH
+
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *  Output staging is based on the "open_memstream()" function, see:
+ *  http://man7.org/linux/man-pages/man3/open_memstream.3.html
+ *  Requires glibc version 2.7 mininal
+ *
+ *  open_memstream returns a FILE stream that allows writing to a 
+ *  dynamically growing buffer, that can be either copied to 
+ *  tcp->outf (syscall successful) or dropped (syscall failed)
+ */
+
+#include "defs.h"
+#if HAVE_OPEN_MEMSTREAM
+
+FILE *
+strace_openmemstream(struct tcb *tcp)
+{
+       FILE *fp        = NULL;  // to be returned 
+
+       if(debug_flag) {
+        ; /* error_msg("stage_openmemstream working on tcp %p", tcp); */
+    }
+       if (NULL != tcp) {
+               tcp->memfptr  = NULL;
+               fp = open_memstream(&(tcp->memfptr), &(tcp->memfloc));
+               if (NULL == fp)
+                       perror_msg_and_die("error during open_memstream");
+               else
+                       /* call to fflush required to update tcp->memfptr, see 
open_memstream man page */
+                       fflush(fp);
+               tcp->memf       = fp;
+               if(debug_flag) {
+            ; /* error_msg("stage_openmemstream for tcp: %p (opened memf: %p, 
memfptr: %p, size: %zu)", tcp, tcp->memf, tcp->memfptr, tcp->memfloc); */
+        }
+       }
+
+       return fp;
+}
+
+void
+drop_staged_out(struct tcb *tcp)
+{
+       if (NULL != tcp->memf) {
+               if(debug_flag) {
+                       ; /* error_msg("drop_stage_out (before flcose): for 
tcp: %p (opened memf: %p, memfptr: %p, size: %zu)", tcp, tcp->memf, 
tcp->memfptr, tcp->memfloc); */
+        }
+
+               if (fclose(tcp->memf)) {
+            perror_msg("flose on tcp->memf");
+        }
+               if (NULL != tcp->memfptr) {
+                       if(debug_flag) {
+                           error_msg("syscall output dropped: %s ...", 
tcp->memfptr); 
+            }
+
+            free(tcp->memfptr);
+            tcp->memfptr = NULL;
+        }
+
+               /* reopen tcp->memf for subsequent use */
+               strace_openmemstream(tcp);
+       }
+}
+
+void
+publish_staged_out(struct tcb *tcp)
+{
+       if (NULL != tcp->memf) {
+               if(debug_flag) {
+                       ; /* error_msg("publish_staged_out (before fclose): for 
tcp: %p (opened memf: %p, memfptr: %p, size: %zu)", tcp, tcp->memf, 
tcp->memfptr, tcp->memfloc); */
+        }
+
+               if (fclose(tcp->memf)) {
+            perror_msg("flose on tcp->memf");
+        }
+               if (NULL != tcp->memfptr) {
+               if (0 > fprintf(tcp->outf, "%s", tcp->memfptr)) {
+                /* ToDo: print suitable error msg */
+            }
+
+                       if (debug_flag) {
+                ; /* error_msg("publish_staged_out (after free): for tcp: %p 
(opened memf: %p, memfptr: %p, size: %zu)", tcp, tcp->memf, tcp->memfptr, 
tcp->memfloc); */
+            }
+
+                       free(tcp->memfptr);
+                       tcp->memfptr = NULL;
+               }
+
+               /* reopen tcp->memf for subsequent use */
+               strace_openmemstream(tcp);
+       }
+}
+#endif /* if HAVE_OPEN_MEMSTREAM */
diff --git a/strace.1 b/strace.1
index 0356c2d..fc5aee4 100644
--- a/strace.1
+++ b/strace.1
@@ -472,7 +472,7 @@ Note that this is independent from the normal tracing of the
 system call which is controlled by the option
 .BR -e "\ " trace = write .
 .TP
-\fB\-e\ 
fault\fR=\,\fIset\/\fR[:\fBerror\fR=\,\fIerrno\/\fR][:\fBsignal\fR=\,\fIsig\/\fR][:\fBwhen\fR=\,\fIexpr\/\fR]
+\fB\-e\ 
fault\fR=\,\fIset\/\fR[:\fBerror\fR=\,\fIerrno\/\fR][:\fBwhen\fR=\,\fIexpr\/\fR]
 Perform a syscall fault injection for the specified set of syscalls.
 When a fault is injected into a syscall invocation, the syscall number
 is replaced by -1 which corresponds to an invalid syscall.
@@ -486,29 +486,8 @@ the default error code returned by the kernel, which is 
traditionally
 .B ENOSYS
 for invalid syscall numbers on most architectures.
 
-If a signal is specified using either a symbolic value like
-.B SIGSEGV
-or a numeric value within 1..\fBSIGRTMAX\fR range,
-that signal is delivered on entering every syscall specified by the
-.IR set .
-
-If :\fBsignal\fR=\,\fIsig\/\fR option is specified without
-:\fBerror\fR=\,\fIerrno\/\fR option, then only a signal
-.I sig
-is delivered without a syscall fault injection.
-Conversely, :\fBerror\fR=\,\fIerrno\/\fR option without
-:\fBsignal\fR=\,\fIsig\/\fR option injects a fault without delivering a signal.
-
-If both :\fBerror\fR=\,\fIerrno\/\fR and :\fBsignal\fR=\,\fIsig\/\fR
-options are specified, then both a fault is injected with the specified
-error code
-.I errno
-and a signal
-.I sig
-is delivered.
-
 Unless a :\fBwhen\fR=\,\fIexpr\fR subexpression is specified,
-an injection is being made into every invocation of each syscall from the
+a fault is injected into every invocation of each syscall from the
 .IR set .
 
 The format of the subexpression is one of the following:
@@ -581,6 +560,12 @@ Print unabbreviated versions of environment, stat, 
termios, etc.
 calls.  These structures are very common in calls and so the default
 behavior displays a reasonable subset of structure members.  Use
 this option to get all of the gory details.
+.TP
+.B \-z
+Print only successful syscalls.
+.TP
+.B \-Z
+Print only failed syscalls.
 .SS Tracing
 .TP 12
 .TP
diff --git a/strace.c b/strace.c
index da6b165..78fcffe 100644
--- a/strace.c
+++ b/strace.c
@@ -3,6 +3,7 @@
  * Copyright (c) 1993 Branko Lankester <bra...@hacktic.nl>
  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <j...@world.std.com>
  * Copyright (c) 1996-1999 Wichert Akkerman <wich...@cistron.nl>
+ * Copyright (C) 2016-2017 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -121,8 +122,12 @@ static int post_attach_sigstop = TCB_IGNORE_ONE_SIGSTOP;
 # define use_seize 0
 #endif
 
-/* Sometimes we want to print only succeeding syscalls. */
-bool not_failing_only = 0;
+/* Sometimes we want to print succeeding/failing syscalls only. */
+bool not_failing_only = false;
+#if HAVE_OPEN_MEMSTREAM
+bool failing_only = false;
+bool stage_output = false;
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
 
 /* Show path associated with fd arguments */
 unsigned int show_fd_path = 0;
@@ -239,7 +244,13 @@ Filtering:\n\
   -e expr        a qualifying expression: option=[!]all or 
option=[!]val1[,val2]...\n\
      options:    trace, abbrev, verbose, raw, signal, read, write, fault\n\
   -P path        trace accesses to path\n\
-\n\
+"
+#if HAVE_OPEN_MEMSTREAM
+"  -z             print only succeeding syscalls\n\
+  -Z             print only failing syscalls\n\
+"
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
+"\n\
 Tracing:\n\
   -b execve      detach on execve syscall\n\
   -D             run tracer process as a detached grandchild, not as parent\n\
@@ -267,9 +278,11 @@ Miscellaneous:\n\
 /* ancient, no one should use it
 -F -- attempt to follow vforks (deprecated, use -f)\n\
  */
+#if HAVE_OPEN_MEMSTREAM == 0 
 /* this is broken, so don't document it
 -z -- print only succeeding syscalls\n\
  */
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
 , DEFAULT_ACOLUMN, DEFAULT_STRLEN, DEFAULT_SORTBY);
        exit(0);
 }
@@ -573,16 +586,43 @@ void
 tprintf(const char *fmt, ...)
 {
        va_list args;
+       int n = 0;
 
        va_start(args, fmt);
+#if HAVE_OPEN_MEMSTREAM
+       if (current_tcp) {
+               if (stage_output) {
+                       if (NULL == current_tcp->memf) {
+                               error_msg("tprintf: No file opened for 
current_tcp->memf\n");
+                               goto ret;
+                       }
+                       n = vfprintf(current_tcp->memf, fmt, args);
+                       if (n < 0) {
+                               perror_msg("printing to memf");
+                       }
+               } else {
+                       n = vfprintf(current_tcp->outf, fmt, args);
+                       if (n < 0) {
+                               if (current_tcp->outf != stderr)
+                                       perror_msg("%s", outfname);
+                       }
+               }
+       }
+
+       if (n >= 0)  {
+               current_tcp->curcol += n;
+       }
+ret:
+#else
        if (current_tcp) {
-               int n = vfprintf(current_tcp->outf, fmt, args);
+               n = vfprintf(current_tcp->outf, fmt, args);
                if (n < 0) {
                        if (current_tcp->outf != stderr)
                                perror_msg("%s", outfname);
                } else
                        current_tcp->curcol += n;
        }
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
        va_end(args);
 }
 
@@ -594,7 +634,21 @@ void
 tprints(const char *str)
 {
        if (current_tcp) {
-               int n = fputs_unlocked(str, current_tcp->outf);
+               int n;
+
+#if HAVE_OPEN_MEMSTREAM
+               if (stage_output) {
+                       if (NULL == current_tcp->memf) {
+                               error_msg("tprints: No file opened for 
current_tcp->memf\n");
+                               return;
+                       }
+                       n = fputs_unlocked(str, current_tcp->memf);
+               } else {
+                       n = fputs_unlocked(str, current_tcp->outf);
+               }
+#else
+               n = fputs_unlocked(str, current_tcp->outf);
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
                if (n >= 0) {
                        current_tcp->curcol += strlen(str);
                        return;
@@ -700,6 +754,11 @@ newoutf(struct tcb *tcp)
                sprintf(name, "%.512s.%u", outfname, tcp->pid);
                tcp->outf = strace_fopen(name);
        }
+#if HAVE_OPEN_MEMSTREAM
+       if (not_failing_only || failing_only) {
+               strace_openmemstream(tcp);
+       }
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
 }
 
 static void
@@ -1606,7 +1665,11 @@ init(int argc, char *argv[])
 #endif
        qualify("signal=all");
        while ((c = getopt(argc, argv,
+#if HAVE_OPEN_MEMSTREAM
+               "+b:cCdfFhiqrtTvVwxyzZ"
+#else
                "+b:cCdfFhiqrtTvVwxyz"
+#endif /* HAVE_OPEN_MEMSTREAM */
 #ifdef USE_LIBUNWIND
                "k"
 #endif
@@ -1680,6 +1743,11 @@ init(int argc, char *argv[])
                case 'z':
                        not_failing_only = 1;
                        break;
+#if HAVE_OPEN_MEMSTREAM
+               case 'Z':
+                       failing_only = 1;
+                       break;
+#endif /* HAVE_OPEN_MEMSTREAM */
                case 'a':
                        acolumn = string_to_uint(optarg);
                        if (acolumn < 0)
@@ -2132,6 +2200,11 @@ print_signalled(struct tcb *tcp, const int pid, int 
status)
 static void
 print_exited(struct tcb *tcp, const int pid, int status)
 {
+#if HAVE_OPEN_MEMSTREAM
+       bool saved_stage_output_flag = stage_output;
+
+       stage_output = false;
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
        if (pid == strace_child) {
                exit_code = WEXITSTATUS(status);
                strace_child = 0;
@@ -2143,11 +2216,19 @@ print_exited(struct tcb *tcp, const int pid, int status)
                tprintf("+++ exited with %d +++\n", WEXITSTATUS(status));
                line_ended();
        }
+#if HAVE_OPEN_MEMSTREAM
+       stage_output = saved_stage_output_flag;
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
 }
 
 static void
 print_stopped(struct tcb *tcp, const siginfo_t *si, const unsigned int sig)
 {
+#if HAVE_OPEN_MEMSTREAM
+       bool saved_stage_output_flag = stage_output;
+
+       stage_output = false;
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
        if (cflag != CFLAG_ONLY_STATS
            && !hide_log(tcp)
            && is_number_in_set(sig, &signal_set)) {
@@ -2160,6 +2241,9 @@ print_stopped(struct tcb *tcp, const siginfo_t *si, const 
unsigned int sig)
                        tprintf("--- stopped by %s ---\n", signame(sig));
                line_ended();
        }
+#if HAVE_OPEN_MEMSTREAM
+       stage_output = saved_stage_output_flag;
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
 }
 
 static void
@@ -2488,13 +2572,26 @@ restart_tracee:
 int
 main(int argc, char *argv[])
 {
+#if HAVE_OPEN_MEMSTREAM
+
+       /* during init don't print to internal memf stream */
+       stage_output = false; 
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
+
        init(argc, argv);
 
        exit_code = !nprocs;
 
+#if HAVE_OPEN_MEMSTREAM
+       stage_output = not_failing_only || failing_only; 
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
        while (trace())
                ;
 
+#if HAVE_OPEN_MEMSTREAM
+       /* during cleanup and shutdown don't print to internal memf stream */
+       stage_output = false;
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
        cleanup();
        fflush(NULL);
        if (shared_log != stderr)
diff --git a/syscall.c b/syscall.c
index 9de3056..68756d7 100644
--- a/syscall.c
+++ b/syscall.c
@@ -6,6 +6,7 @@
  * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *                     Linux for s390 port by D.J. Barrow
  *                    <barrow...@mail.yahoo.com,djbar...@de.ibm.com>
+ * Copyright (C) 2016-2017 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -804,8 +805,20 @@ trace_syscall_exiting(struct tcb *tcp)
         * whereas the intended result is that open(...) line
         * is not shown at all.
         */
+#if HAVE_OPEN_MEMSTREAM
+               if (stage_output) {
+            if ( (not_failing_only && syserror(tcp) ) || (failing_only && 
!syserror(tcp)) ) {
+                drop_staged_out(tcp);
+                line_ended();
+                goto ret;      /* ignore failed/successful syscalls */
+            }
+               } else {
+                       /* publish staged output later */
+               }
+#else
                if (not_failing_only && tcp->u_error)
                        goto ret;       /* ignore failed syscalls */
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
                if (tcp->sys_func_rval & RVAL_DECODED)
                        sys_res = tcp->sys_func_rval;
                else
@@ -952,6 +965,11 @@ trace_syscall_exiting(struct tcb *tcp)
        }
        tprints("\n");
        dumpio(tcp);
+#if HAVE_OPEN_MEMSTREAM
+       if (stage_output) {
+               publish_staged_out(tcp);
+       }
+#endif  /* #if HAVE_OPEN_MEMSTREAM */
        line_ended();
 
 #ifdef USE_LIBUNWIND
-- 
1.9.1


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to