]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
When generating XML output for suppressions, print the suppression
authorJulian Seward <jseward@acm.org>
Sat, 15 Aug 2009 22:41:51 +0000 (22:41 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 15 Aug 2009 22:41:51 +0000 (22:41 +0000)
both wrapped up in XML tags (as before) but also in plain text in a
sequence of CDATA blocks.  Normally only one, but in the worst case
the raw data will have ]]> in it, in which case it needs to be split
across two CDATA blocks.

This apparently simple change involved a lot of refactoring of the
suppression printing machinery:

* in the core-tool iface, change "print_extra_suppression_info" (which
  prints any auxiliary info) to "get_extra_suppression_info", which
  parks the text in a caller-supplied buffer.  Adjust tools to match.

* VG_(apply_StackTrace): accept a void* argument, which is passed to
  each invokation of the functional parameter (a poor man's closure
  implementation).

* move PRINTF_CHECK into put_tool_basics.h, where it should have been
  all along

* move private printf-into-an-XArray-of-character functions from
  m_debuginfo into m_xarray, and make them public

* gen_suppression itself: use all the above changes.  Basically we
  always generate the plaintext version into an XArray.  In text mode
  that's just printed.  In XML mode, we print the XMLery as before,
  but the plaintext version is dumped into a CDATA block too.

* update the Protocol 4 specification to match all this.

This still isn't 100% right in the sense that the CDATA block data
needs to be split across multiple blocks if it should ever contain the
CDATA end mark "]]>".  The Protocol 4 spec has this right even though
the implementation currently doesn't.

Fixes #191189.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10822

22 files changed:
coregrind/m_debuginfo/debuginfo.c
coregrind/m_errormgr.c
coregrind/m_stacktrace.c
coregrind/m_tooliface.c
coregrind/m_xarray.c
coregrind/pub_core_tooliface.h
docs/internals/xml-output-protocol4.txt
drd/drd_error.c
exp-ptrcheck/pc_common.c
exp-ptrcheck/pc_common.h
exp-ptrcheck/pc_main.c
helgrind/hg_errors.c
helgrind/hg_errors.h
helgrind/hg_main.c
include/pub_tool_basics.h
include/pub_tool_libcprint.h
include/pub_tool_stacktrace.h
include/pub_tool_tooliface.h
include/pub_tool_xarray.h
memcheck/mc_errors.c
memcheck/mc_include.h
memcheck/mc_main.c

index e280b933681440ac71b8ab2d88efd36a1ba56bfa..bb2016f14e3687e7f53cfd88aff44a4c4894403b 100644 (file)
@@ -2269,28 +2269,18 @@ Bool VG_(use_FPO_info) ( /*MOD*/Addr* ipP,
 /*---                                                        ---*/
 /*--------------------------------------------------------------*/
 
-/* Implement a "p2XA" function ("printf-to-XA"), which printfs into an
-   XArray of HChar, adding stuff at the end.  This is very convenient
-   for concocting result strings in format_message().  Note that the
-   resulting string is NOT zero-terminated.
+/* Try to make p2XA(dst, fmt, args..) turn into
+   VG_(xaprintf_no_f_c)(dst, fmt, args) without having to resort to
+   vararg macros.  As usual with everything to do with varargs, it's
+   an ugly hack.
 
-   Unfortunately no format check on p2XA, since we need to use %t
-   for XML escaped-string output, and gcc complains about that.
+   //#define p2XA(dstxa, format, args...)
+   //   VG_(xaprintf_no_f_c)(dstxa, format, ##args)
 */
-static void add_char_to_XA ( HChar c, void* opaque )
-{
-   XArray* dst = (XArray*)opaque;
-   (void) VG_(addBytesToXA)( dst, &c, 1 );
-}
-static void p2XA ( XArray* dst, const HChar* format, ... )
-{
-   va_list vargs;
-   va_start(vargs, format);
-   VG_(vcbprintf)( add_char_to_XA, (void*)dst, format, vargs );
-   va_end(vargs);
-}
+#define  p2XA  VG_(xaprintf_no_f_c)
 
-/* Add a zero-terminating byte to DST. */
+/* Add a zero-terminating byte to DST, which must be an XArray* of
+   HChar. */
 static void zterm_XA ( XArray* dst )
 {
    HChar zero = 0;
index 4948c18e2510840f433c247fc9caa1c9a3386e97..3891b5c0b582037ac7dc49f1a8723dce524ec275 100644 (file)
@@ -46,6 +46,7 @@
 #include "pub_core_stacktrace.h"
 #include "pub_core_tooliface.h"
 #include "pub_core_translate.h"        // for VG_(translate)()
+#include "pub_core_xarray.h"           // VG_(xaprintf) et al
 
 /*------------------------------------------------------------*/
 /*--- Globals                                              ---*/
@@ -295,78 +296,133 @@ static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
 }
 
 
-/* Helper function for suppression generation: print a single line of
-   a suppression pseudo-stack-trace, either in XML or text mode.
+/* Helper functions for suppression generation: print a single line of
+   a suppression pseudo-stack-trace, either in XML or text mode.  It's
+   important that the behaviour of these two functions exactly
+   corresponds.
 */
 #define ERRTXT_LEN   4096
 
-static void printSuppForIp(UInt n, Addr ip)
+static void printSuppForIp_XML(UInt n, Addr ip, void* uu_opaque)
 {
    static UChar buf[ERRTXT_LEN];
-
    if ( VG_(get_fnname_no_cxx_demangle) (ip, buf,  ERRTXT_LEN) ) {
-      if (VG_(clo_xml))
-         VG_(printf_xml_no_f_c)("    <sframe> <fun>%t</fun> </sframe>\n", buf);
-      else
-         VG_(printf)("   fun:%s\n", buf);
-  } else if ( VG_(get_objname)(ip, buf, ERRTXT_LEN) ) {
-      if (VG_(clo_xml))
-         VG_(printf_xml_no_f_c)("    <sframe> <obj>%t</obj> </sframe>\n", buf);
-      else
-         VG_(printf)("   obj:%s\n", buf);
-
+      VG_(printf_xml_no_f_c)("    <sframe> <fun>%t</fun> </sframe>\n", buf);
+   } else
+   if ( VG_(get_objname)(ip, buf, ERRTXT_LEN) ) {
+      VG_(printf_xml_no_f_c)("    <sframe> <obj>%t</obj> </sframe>\n", buf);
    } else {
-      if (VG_(clo_xml))
-         VG_(printf_xml_no_f_c)("    <sframe> <obj>*</obj> </sframe>\n");
-      else
-         VG_(printf)("   obj:*\n");
+      VG_(printf_xml_no_f_c)("    <sframe> <obj>*</obj> </sframe>\n");
    }
 }
 
+static void printSuppForIp_nonXML(UInt n, Addr ip, void* textV)
+{
+   static UChar buf[ERRTXT_LEN];
+   XArray* /* of HChar */ text = (XArray*)textV;
+   if ( VG_(get_fnname_no_cxx_demangle) (ip, buf,  ERRTXT_LEN) ) {
+      VG_(xaprintf)(text, "   fun:%s\n", buf);
+   } else
+   if ( VG_(get_objname)(ip, buf, ERRTXT_LEN) ) {
+      VG_(xaprintf)(text, "   obj:%s\n", buf);
+   } else {
+      VG_(xaprintf)(text, "   obj:*\n");
+   }
+}
 
 /* Generate a suppression for an error, either in text or XML mode.
 */
 static void gen_suppression(Error* err)
 {
-   ExeContext* ec      = VG_(get_error_where)(err);
+   Char        xtra[256]; /* assumed big enough (is overrun-safe) */
+   Bool        anyXtra;
+   Char*       name;
+   ExeContext* ec;
+   XArray* /* HChar */ text;
+
+   const HChar* dummy_name = "insert_a_suppression_name_here";
+
+   vg_assert(err);
+
+   /* In XML mode, we also need to print the plain text version of the
+      suppresion in a CDATA section.  What that really means is, we
+      need to generate the plaintext version both in XML and text
+      mode.  So generate it into TEXT. */
+   text = VG_(newXA)( VG_(malloc), "errormgr.gen_suppression.1",
+                      VG_(free), sizeof(HChar) );
+   vg_assert(text);
+
+   ec = VG_(get_error_where)(err);
+   vg_assert(ec);
+
+   name = VG_TDICT_CALL(tool_get_error_name, err);
+   if (NULL == name) {
+      VG_(umsg)("(%s does not allow error to be suppressed)\n",
+                VG_(details).name);
+      return;
+   }
 
-   //(example code, see comment on CoreSuppKind above)
-   if (0) {    
-   //if (0) ThreadErr == err->ekind) {
-   //   VG_(printf)("{\n");
-   //   VG_(printf)("   <insert a suppression name here>\n");
-   //   VG_(printf)("   core:Thread\n");
+   /* Ok.  Generate the plain text version into TEXT. */
+   VG_(xaprintf)(text, "{\n");
+   VG_(xaprintf)(text, "   <%s>\n", dummy_name);
+   VG_(xaprintf)(text, "   %s:%s\n", VG_(details).name, name);
 
-   } else {
-      Char* name = VG_TDICT_CALL(tool_get_error_name, err);
-      if (NULL == name) {
-         VG_(umsg)("(%s does not allow error to be suppressed)\n",
-                   VG_(details).name);
-         return;
-      }
-      if (VG_(clo_xml)) {
-         VG_(printf_xml)("  <suppression>\n");
-         VG_(printf_xml)("    <sname>insert_a_suppression_name_here</sname>\n");
-         VG_(printf_xml)("    <skind>%s:%s</skind>\n", VG_(details).name, name);
-      } else {
-         VG_(printf)("{\n");
-         VG_(printf)("   <insert a suppression name here>\n");
-         VG_(printf)("   %s:%s\n", VG_(details).name, name);
-      }
-      VG_TDICT_CALL(tool_print_extra_suppression_info, err);
-   }
+   VG_(memset)(xtra, 0, sizeof(xtra));
+   anyXtra = VG_TDICT_CALL(tool_get_extra_suppression_info,
+                           err, xtra, sizeof(xtra));
+   vg_assert(xtra[sizeof(xtra)-1] == 0);
+
+   if (anyXtra)
+      VG_(xaprintf)(text, "   %s\n", xtra);
 
    // Print stack trace elements
-   VG_(apply_StackTrace)(printSuppForIp,
+   VG_(apply_StackTrace)(printSuppForIp_nonXML,
+                         text,
                          VG_(get_ExeContext_StackTrace)(ec),
                          VG_(get_ExeContext_n_ips)(ec));
 
-   if (VG_(clo_xml)) {
-      VG_(printf_xml)("  </suppression>\n");
+   VG_(xaprintf)(text, "}\n");
+   // zero terminate
+   VG_(xaprintf)(text, "%c", (HChar)0 );
+   // VG_(printf) of text
+
+   /* And now display it. */
+   if (! VG_(clo_xml) ) {
+
+      // the simple case
+      VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) );
+
    } else {
-      VG_(printf)("}\n");
+
+      /* Now we have to print the XML directly.  No need to go to the
+         effort of stuffing it in an XArray, since we won't need it
+         again. */
+      VG_(printf_xml)("  <suppression>\n");
+      VG_(printf_xml)("    <sname>%s</sname>\n", dummy_name);
+      VG_(printf_xml_no_f_c)(
+                      "    <skind>%t:%t</skind>\n", VG_(details).name, name);
+      if (anyXtra)
+         VG_(printf_xml_no_f_c)("    <skaux>%t</skaux>\n", xtra);
+
+      // Print stack trace elements
+      VG_(apply_StackTrace)(printSuppForIp_XML,
+                            NULL,
+                            VG_(get_ExeContext_StackTrace)(ec),
+                            VG_(get_ExeContext_n_ips)(ec));
+
+      // And now the cdata bit
+      // XXX FIXME!  properly handle the case where the raw text
+      // itself contains "]]>", as specified in Protocol 4.
+      VG_(printf_xml)("    <rawtext>\n");
+      VG_(printf_xml)("<![CDATA[\n");
+      VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) );
+      VG_(printf_xml)("]]>\n");
+      VG_(printf_xml)("    </rawtext>\n");
+      VG_(printf_xml)("  </suppression>\n");
+
    }
+
+   VG_(deleteXA)(text);
 }
 
 
index 130107afa4a6532ffad899803c8eff9672a60a60..42e0b978d828657cfad19df6f71b041e0e1e6194 100644 (file)
@@ -514,7 +514,7 @@ UInt VG_(get_StackTrace) ( ThreadId tid,
                                        stack_highest_word);
 }
 
-static void printIpDesc(UInt n, Addr ip)
+static void printIpDesc(UInt n, Addr ip, void* uu_opaque)
 {
    #define BUF_LEN   4096
    
@@ -537,7 +537,7 @@ void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
    if (VG_(clo_xml))
       VG_(printf_xml)("  <stack>\n");
 
-   VG_(apply_StackTrace)( printIpDesc, ips, n_ips );
+   VG_(apply_StackTrace)( printIpDesc, NULL, ips, n_ips );
 
    if (VG_(clo_xml))
       VG_(printf_xml)("  </stack>\n");
@@ -555,8 +555,11 @@ void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt max_n_ips )
    VG_(pp_StackTrace)(ips, n_ips);
 }
 
-void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
-                            StackTrace ips, UInt n_ips )
+void VG_(apply_StackTrace)(
+        void(*action)(UInt n, Addr ip, void* opaque),
+        void* opaque,
+        StackTrace ips, UInt n_ips
+     )
 {
    Bool main_done = False;
    Int i = 0;
@@ -576,7 +579,7 @@ void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
       }
 
       // Act on the ip
-      action(i, ip);
+      action(i, ip, opaque);
 
       i++;
    } while (i < n_ips && !main_done);
index 6f76d5978882b746fb48593fc1339c07871a887e..c59e59b73f923caa531dc3302b8f02d2e6dd614e 100644 (file)
@@ -233,7 +233,7 @@ void VG_(needs_tool_errors)(
    Bool (*read_extra) (Int, Char**, SizeT*, Supp*),
    Bool (*matches)    (Error*, Supp*),
    Char* (*name)      (Error*),
-   void (*print_extra)(Error*)
+   Bool (*get_xtra_si)(Error*,/*OUT*/Char*,Int)
 )
 {
    VG_(needs).tool_errors = True;
@@ -246,7 +246,7 @@ void VG_(needs_tool_errors)(
    VG_(tdict).tool_read_extra_suppression_info  = read_extra;
    VG_(tdict).tool_error_matches_suppression    = matches;
    VG_(tdict).tool_get_error_name               = name;
-   VG_(tdict).tool_print_extra_suppression_info = print_extra;
+   VG_(tdict).tool_get_extra_suppression_info   = get_xtra_si;
 }
 
 void VG_(needs_command_line_options)(
index c00391b0104db3da54a8fd961472d4a1161543e2..eef668b8c1bb14f90babf1775525a72e9c003910 100644 (file)
@@ -306,6 +306,31 @@ void VG_(dropHeadXA) ( XArray* xao, Word n )
    xa->usedsizeE -= n;
 }
 
+/* --------- Printeffery --------- */
+
+static void add_char_to_XA ( HChar c, void* opaque )
+{
+   XArray* dst = (XArray*)opaque;
+   (void) VG_(addBytesToXA)( dst, &c, 1 );
+}
+
+void VG_(xaprintf)( XArray* dst, const HChar* format, ... )
+{
+   va_list vargs;
+   va_start(vargs, format);
+   VG_(vcbprintf)( add_char_to_XA, (void*)dst, format, vargs );
+   va_end(vargs);
+}
+
+/* and again .. */
+void VG_(xaprintf_no_f_c)( XArray* dst, const HChar* format, ... )
+{
+   va_list vargs;
+   va_start(vargs, format);
+   VG_(vcbprintf)( add_char_to_XA, (void*)dst, format, vargs );
+   va_end(vargs);
+}
+
 
 /*--------------------------------------------------------------------*/
 /*--- end                                               m_xarray.c ---*/
index 9e928cb4916538584be6f5fd887f161bf5c48d13..e5785054e06cad65e809296851993774b8ac5c86 100644 (file)
@@ -125,7 +125,7 @@ typedef struct {
    Bool  (*tool_read_extra_suppression_info) (Int, Char**, SizeT*, Supp*);
    Bool  (*tool_error_matches_suppression)   (Error*, Supp*);
    Char* (*tool_get_error_name)              (Error*);
-   void  (*tool_print_extra_suppression_info)(Error*);
+   Bool  (*tool_get_extra_suppression_info)  (Error*,/*OUT*/Char*,Int);
 
    // VG_(needs).superblock_discards
    void (*tool_discard_superblock_info)(Addr64, VexGuestExtents);
index 98bce27ec7316b61c4109c1982d16f0080c41bca..7da70a99a04d34ea75eab747d49b09174eeb8424 100644 (file)
@@ -298,14 +298,26 @@ SUPPRESSION
 -----------
 These are optionally emitted as part of ERRORs, and specify the
 suppression that would be needed to suppress the containing error.
+For convenience, the suppression is presented twice, once in
+a structured nicely wrapped up in tags, and once as raw text
+suitable for direct copying and pasting into a suppressions file.
 
   <suppression>
     <sname>TEXT</sname>    name of the suppression
     <skind>TEXT</skind>    kind, eg                 "Memcheck:Param"
     <skaux>TEXT</skaux>    (optional) aux kind, eg  "write(buf)"
     SFRAME                 (one or more) frames
+    <rawtext> CDATAS </rawtext>
   </suppression>
 
+where CDATAS is a sequence of one or more <![CDATA[ .. ]]> blocks
+holding the raw text.  Unfortunately, CDATA provides no way to escape
+the ending marker "]]>", which means that if the raw data contains
+such a sequence, it has to be split between two CDATA blocks, one
+ending with data "]]" and the other beginning with data "<".  This is
+why the spec calls for one or more CDATA blocks rather than exactly
+one.
+
 
 SFRAME
 ------
index 4b1c2fad9d6c4737d6a7827ed2601d9d9b8899d2..7b1b8a52ca95a4beca8ddb5e27dbce2a205fae75 100644 (file)
@@ -528,14 +528,18 @@ static Char* drd_get_error_name(Error* e)
 }
 
 /**
- * Print extra suppression information.
+ * Return extra suppression information.
  *
  * Invoked while printing a suppression pattern because the user
  * specified --gen-suppressions=yes or all on the command line. DRD does not
  * define any 'extra' suppression information.
  */
-static void drd_print_extra_suppression_info(Error* e)
-{ }
+static
+Bool drd_get_extra_suppression_info(Error* e,
+                                    /*OUT*/Char* buf, Int nBuf)
+{
+   return False;
+}
 
 /** Tell the Valgrind core about DRD's error handlers. */
 void DRD_(register_error_handlers)(void)
@@ -549,5 +553,5 @@ void DRD_(register_error_handlers)(void)
                           drd_read_extra_suppression_info,
                           drd_error_matches_suppression,
                           drd_get_error_name,
-                          drd_print_extra_suppression_info);
+                          drd_get_extra_suppression_info);
 }
index 0421e6ba46b7397a17f3bdea7088645a8ce9d317..a45c41632750c7bbcca48231961809b03e3afd44 100644 (file)
@@ -775,16 +775,23 @@ Char* pc_get_error_name ( Error* err )
    }
 }
 
-void pc_print_extra_suppression_info ( Error* err )
+Bool pc_get_extra_suppression_info ( Error* err,
+                                     /*OUT*/Char* buf, Int nBuf )
 {
-   if (XE_SysParam == VG_(get_error_kind)(err)) {
-      VG_(printf)("   %s\n", VG_(get_error_string)(err));
+   ErrorKind ekind = VG_(get_error_kind )(err);
+   tl_assert(buf);
+   tl_assert(nBuf >= 16); // stay sane
+   if (XE_SysParam == ekind) {
+      Char* errstr = VG_(get_error_string)(err);
+      tl_assert(errstr);
+      VG_(snprintf)(buf, nBuf-1, "%s", errstr);
+      return True;
+   } else {
+      return False;
    }
 }
 
 
-
-
 /*--------------------------------------------------------------------*/
 /*--- end                                              pc_common.c ---*/
 /*--------------------------------------------------------------------*/
index 1e2549af4c193ef260910c513bcebbc86bab29a5..4772008dca168cf82ddc275c7039ed4a1e5f3a30 100644 (file)
@@ -56,7 +56,8 @@ Bool pc_read_extra_suppression_info ( Int fd, Char** bufpp,
                                       SizeT* nBufp, Supp* su );
 Bool pc_error_matches_suppression (Error* err, Supp* su);
 Char* pc_get_error_name ( Error* err );
-void pc_print_extra_suppression_info ( Error* err );
+Bool pc_get_extra_suppression_info ( Error* err,
+                                     /*OUT*/Char* buf, Int nBuf );
 
 extern Bool h_clo_partial_loads_ok;
 /* extern Bool h_clo_lossage_check; */
index 436dba0136fe75acf80ff71043d928f43b1c2ef9..64bee725720ecbe2454eb7ac6654c1a306ff7cd4 100644 (file)
@@ -190,7 +190,7 @@ static void pc_pre_clo_init(void)
                                  pc_read_extra_suppression_info,
                                  pc_error_matches_suppression,
                                  pc_get_error_name,
-                                 pc_print_extra_suppression_info);
+                                 pc_get_extra_suppression_info);
 
    VG_(needs_xml_output)        ();
 
index 6897e317e5bf807e112d0df2aee675acf19a847c..f5649bc24516817c1d8c0e907b7ac9de432d35d7 100644 (file)
@@ -1068,9 +1068,11 @@ Bool HG_(error_matches_suppression) ( Error* err, Supp* su )
    }
 }
 
-void HG_(print_extra_suppression_info) ( Error* err )
+Bool HG_(get_extra_suppression_info) ( Error* err,
+                                       /*OUT*/Char* buf, Int nBuf )
 {
    /* Do nothing */
+   return False;
 }
 
 
index 6b97f488c2a5a408687940d3516926607e8aa8f7..ee4949185331752c4d1b6cd30a948c7e1f57bef7 100644 (file)
@@ -44,7 +44,8 @@ Bool  HG_(read_extra_suppression_info) ( Int fd, Char** bufpp, SizeT* nBufp,
                                          Supp* su );
 Bool  HG_(error_matches_suppression) ( Error* err, Supp* su );
 Char* HG_(get_error_name) ( Error* err );
-void  HG_(print_extra_suppression_info) ( Error* err );
+Bool  HG_(get_extra_suppression_info) ( Error* err,
+                                        /*OUT*/Char* buf, Int nBuf );
 
 /* Functions for recording various kinds of errors. */
 void HG_(record_error_Race) ( Thread* thr, 
index 3a53f7129e54db8baa50c1c7079ec662a43d6304..2e4ff1d8d30c9a6025b14b53693a68d0b04a6ec5 100644 (file)
@@ -4601,7 +4601,7 @@ static void hg_pre_clo_init ( void )
                                    HG_(read_extra_suppression_info),
                                    HG_(error_matches_suppression),
                                    HG_(get_error_name),
-                                   HG_(print_extra_suppression_info));
+                                   HG_(get_extra_suppression_info));
 
    VG_(needs_xml_output)          ();
 
index 734391c1d9b52e94e96dcbf1c59c65c18b72324d..e66456136d68a2860c4ea17500e10be2307c95f5 100644 (file)
@@ -323,6 +323,16 @@ static inline Bool sr_EQ ( SysRes sr1, SysRes sr2 ) {
 #  define UNLIKELY(x) (x)
 #endif
 
+// printf format string checking for gcc.
+// This feature has been supported since at least gcc version 2.95.
+// For more information about the format attribute, see
+// http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html.
+#if defined(__GNUC__)
+#define PRINTF_CHECK(x, y) __attribute__((format(__printf__, x, y)))
+#else
+#define PRINTF_CHECK(x, y)
+#endif
+
 
 #endif /* __PUB_TOOL_BASICS_H */
 
index dd92feebcb6a38efad9a75bc21f0b705f8446753..0e057cbba0f707e3c639c5701a9dfa405f9082f8 100644 (file)
 #ifndef __PUB_TOOL_LIBCPRINT_H
 #define __PUB_TOOL_LIBCPRINT_H
 
-
-/* Enable compile-time format string checking by gcc.
-   This feature is supported since at least gcc version 2.95.
-   For more information about the format attribute, see also
-   http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html.
- */
-
-#if defined(__GNUC__)
-#define PRINTF_CHECK(x, y) __attribute__((format(__printf__, x, y)))
-#else
-#define PRINTF_CHECK(x, y)
-#endif
-
-
 /* ---------------------------------------------------------------------
    Basic printing
    ------------------------------------------------------------------ */
index f17758bb27319e3a2616fc6719df99c54b860483..6792c69c696ef9fed65d1dca99e531040ee8ce7c 100644 (file)
@@ -62,11 +62,16 @@ extern UInt VG_(get_StackTrace) ( ThreadId tid,
                                   /*OUT*/StackTrace fps,
                                   Word first_ip_delta );
 
-// Apply a function to every element in the StackTrace.  The parameter 'n'
-// gives the index of the passed ip.  Doesn't go below main() unless
-// --show-below-main=yes is set.
-extern void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
-                                   StackTrace ips, UInt n_ips );
+// Apply a function to every element in the StackTrace.  The parameter
+// 'n' gives the index of the passed ip.  'opaque' is an arbitrary
+// pointer provided to each invokation of 'action' (a poor man's
+// closure).  Doesn't go below main() unless --show-below-main=yes is
+// set.
+extern void VG_(apply_StackTrace)(
+               void(*action)(UInt n, Addr ip, void* opaque),
+               void* opaque,
+               StackTrace ips, UInt n_ips
+            );
 
 // Print a StackTrace.
 extern void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips );
index 19f2c4c419b00039cc193fccaf61e01f0f4a704b..fa8d10410cd107dbc5c13fac1a95128901871b29 100644 (file)
@@ -332,10 +332,17 @@ extern void VG_(needs_tool_errors) (
    // VG_(tdict).tool_recognised_suppression().
    Char* (*get_error_name)(Error* err),
 
-   // This should print any extra info for the error, for --gen-suppressions,
-   // including the newline.  This is the inverse of
+   // This should print into buf[0..nBuf-1] any extra info for the
+   // error, for --gen-suppressions, but not including any leading
+   // spaces nor a trailing newline.  When called, buf[0 .. nBuf-1]
+   // will be zero filled, and it is expected and checked that the
+   // last element is still zero after the call.  In other words the
+   // tool may not overrun the buffer, and this is checked for.  If
+   // there is any info printed in the buffer, return True, otherwise
+   // do nothing, and return False.  This function is the inverse of
    // VG_(tdict).tool_read_extra_suppression_info().
-   void (*print_extra_suppression_info)(Error* err)
+   Bool (*print_extra_suppression_info)(Error* err,
+                                        /*OUT*/Char* buf, Int nBuf)
 );
 
 /* Is information kept by the tool about specific instructions or
index 8e6cdcf191ece6e99fada4e2b37a80039df9f69a..d9147f85da706b77ce4137032008a721e9ccae2d 100644 (file)
@@ -125,6 +125,18 @@ extern void VG_(dropHeadXA) ( XArray*, Word );
    is NULL, in which case the parent's cost-center is used. */
 extern XArray* VG_(cloneXA)( HChar* cc, XArray* xa );
 
+/* Convenience function: printf into an XArray of HChar, adding stuff
+   at the end.  This is very convenient for concocting arbitrary
+   length printf output in an XArray.  Note that the resulting string
+   is NOT zero-terminated.  Versions are provided with and without a
+   format check, the latter so the unknown (to gcc) "%t" can be used
+   without gcc complaining. */
+extern void VG_(xaprintf)( XArray* dst, const HChar* format, ... )
+                         PRINTF_CHECK(2, 3);
+
+extern void VG_(xaprintf_no_f_c)
+                         ( XArray* dst, const HChar* format, ... );
+
 #endif   // __PUB_TOOL_XARRAY_H
 
 /*--------------------------------------------------------------------*/
index 441c991d9cfeb4a77e77ba28b205c86da6404a46..5ee105506658df35675d07b4a16ade809c66eb43 100644 (file)
@@ -1499,11 +1499,19 @@ Char* MC_(get_error_name) ( Error* err )
    }
 }
 
-void MC_(print_extra_suppression_info) ( Error* err )
+Bool MC_(get_extra_suppression_info) ( Error* err,
+                                       /*OUT*/Char* buf, Int nBuf )
 {
    ErrorKind ekind = VG_(get_error_kind )(err);
+   tl_assert(buf);
+   tl_assert(nBuf >= 16); // stay sane
    if (Err_RegParam == ekind || Err_MemParam == ekind) {
-      VG_(printf)("   %s\n", VG_(get_error_string)(err));
+      Char* errstr = VG_(get_error_string)(err);
+      tl_assert(errstr);
+      VG_(snprintf)(buf, nBuf-1, "%s", errstr);
+      return True;
+   } else {
+      return False;
    }
 }
 
index 920378362aa0900a0480033b4e4e6ce75ad25b0f..1032cf5ea5b3dd3521d94277798cbb25d39d95d1 100644 (file)
@@ -320,7 +320,8 @@ Bool MC_(read_extra_suppression_info) ( Int fd, Char** buf,
 
 Bool MC_(error_matches_suppression) ( Error* err, Supp* su );
 
-void MC_(print_extra_suppression_info) ( Error* err );
+Bool MC_(get_extra_suppression_info) ( Error* err,
+                                       /*OUT*/Char* buf, Int nBuf );
 
 Char* MC_(get_error_name) ( Error* err );
 
index ffe75917f2cd16ed405d5e4fcf4be10ba9e053d6..c262d69d761b419c18e591c639a841897fa3214a 100644 (file)
@@ -5715,7 +5715,7 @@ static void mc_pre_clo_init(void)
                                    MC_(read_extra_suppression_info),
                                    MC_(error_matches_suppression),
                                    MC_(get_error_name),
-                                   MC_(print_extra_suppression_info));
+                                   MC_(get_extra_suppression_info));
    VG_(needs_libc_freeres)        ();
    VG_(needs_command_line_options)(mc_process_cmd_line_options,
                                    mc_print_usage,