Hello All,

I had submitted below patch back 18th of  January 
(https://sourceforge.net/p/strace/mailman/message/35611809/). Don't see that it 
was merged nor did I receive any feedback so far.
Was my submission just missed - or is the implemented feature (-z/-Z: filter 
for successful/failed syscalls) considered not useful for the project?

Regards,
Burkhard 

-----Original Message-----
From: Kohl, Burkhard 
Sent: Wednesday, January 18, 2017 18:13
To: strace-devel@lists.sourceforge.net
Cc: Kohl, Burkhard <burkhard.k...@intel.com>
Subject: [PATCH v2] Implement output staging for failed/successful syscalls

  With not_failing_only/failing_only flags, syscall output
  is written to tcp->memf and either dropped or published
  at strace_syscall_exiting

* stage_out.c 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    add option -Z +help
              modified tprintf, tprints
              set stage_output in main().
* Makefile.am new: stage_out.c
* configure.ac (AC_CHECK_FUNCS): open_memstream
* strace.1    -z/-Z: description added
---
 Makefile.am  |   1 +
 configure.ac |   1 +
 defs.h       |  18 +++++++++
 stage_out.c  | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 strace.1     |   6 +++
 strace.c     | 107 +++++++++++++++++++++++++++++++++++++++++++++++++---
 syscall.c    |  18 +++++++++
 7 files changed, 266 insertions(+), 5 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..7494e54 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;
+#if HAVE_OPEN_MEMSTREAM
+extern bool failing_only;
+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..08739c0 100644
--- a/strace.1
+++ b/strace.1
@@ -581,6 +581,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 successful syscalls only.
+.TP
+.B \-Z
+Print failed syscalls only.
 .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..a9be536 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 @@ 
-796,6 +797,17 @@ trace_syscall_exiting(struct tcb *tcp)
        if (tcp->qual_flg & QUAL_RAW) {
                /* sys_res = printargs(tcp); - but it's nop on sysexit */
        } else {
+#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
        /* FIXME: not_failing_only (IOW, option -z) is broken:
         * failure of syscall is known only after syscall return.
         * Thus we end up with something like this on, say, ENOENT:
@@ -806,6 +818,7 @@ trace_syscall_exiting(struct tcb *tcp)
         */
                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

Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Christian Lamprechter
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928


------------------------------------------------------------------------------
Announcing the Oxford Dictionaries API! The API offers world-renowned
dictionary content that is easy and intuitive to access. Sign up for an
account today to start using our lexical data to power your apps and
projects. Get started today and enter our developer competition.
http://sdm.link/oxford
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to