/*--- ---*/
/*--------------------------------------------------------------*/
-/* 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;
#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 ---*/
}
-/* 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);
}
stack_highest_word);
}
-static void printIpDesc(UInt n, Addr ip)
+static void printIpDesc(UInt n, Addr ip, void* uu_opaque)
{
#define BUF_LEN 4096
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");
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;
}
// Act on the ip
- action(i, ip);
+ action(i, ip, opaque);
i++;
} while (i < n_ips && !main_done);
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;
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)(
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 ---*/
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);
-----------
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
------
}
/**
- * 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)
drd_read_extra_suppression_info,
drd_error_matches_suppression,
drd_get_error_name,
- drd_print_extra_suppression_info);
+ drd_get_extra_suppression_info);
}
}
}
-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 ---*/
/*--------------------------------------------------------------------*/
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; */
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) ();
}
}
-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;
}
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,
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) ();
# 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 */
#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
------------------------------------------------------------------ */
/*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 );
// 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
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
/*--------------------------------------------------------------------*/
}
}
-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;
}
}
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 );
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,