When XML mode is selected messages from VALGRIND_PRINTF and friends
should go to the XML stream not stderr. Fixes BZ 322807.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13516 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/NEWS b/NEWS
index 76939f8..d5770a5 100644
--- a/NEWS
+++ b/NEWS
@@ -443,6 +443,9 @@
321960 pthread_create() then alloca() causing invalid stack write errors
FIXED 13467
+322807 VALGRIND_PRINTF_BACKTRACE writes callstack to xml and text to stderr
+ FIXED 13516
+
322851 0bXXX binary literal syntax is not standard
FIXED 2736
diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c
index eb3351e..b20ab91 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -1654,6 +1654,76 @@
}
+/* Write out a client message, possibly including a back trace. Return
+ the number of characters written. In case of XML output, the format
+ string as well as any arguments it requires will be XML'ified.
+ I.e. special characters such as the angle brackets will be translated
+ into proper escape sequences. */
+static
+Int print_client_message( ThreadId tid, const HChar *format,
+ va_list *vargsp, Bool include_backtrace)
+{
+ Int count;
+
+ if (VG_(clo_xml)) {
+ /* Translate the format string as follows:
+ < --> <
+ > --> >
+ & --> &
+ %s --> %pS
+ Yes, yes, it's simplified but in synch with
+ myvprintf_str_XML_simplistic and VG_(debugLog_vprintf).
+ */
+
+ /* Allocate a buffer that is for sure large enough. */
+ HChar xml_format[VG_(strlen)(format) * 5 + 1];
+
+ const HChar *p;
+ HChar *q = xml_format;
+
+ for (p = format; *p; ++p) {
+ switch (*p) {
+ case '<': VG_(strcpy)(q, "<"); q += 4; break;
+ case '>': VG_(strcpy)(q, ">"); q += 4; break;
+ case '&': VG_(strcpy)(q, "&"); q += 5; break;
+ case '%':
+ /* Careful: make sure %%s stays %%s */
+ *q++ = *p++;
+ if (*p == 's') {
+ *q++ = 'p';
+ *q++ = 'S';
+ } else {
+ *q++ = *p;
+ }
+ break;
+
+ default:
+ *q++ = *p;
+ break;
+ }
+ }
+ *q = '\0';
+
+ VG_(printf_xml)( "<clientmsg>\n" );
+ VG_(printf_xml)( " <tid>%d</tid>\n", tid );
+ VG_(printf_xml)( " <text>" );
+ count = VG_(vprintf_xml)( xml_format, *vargsp );
+ VG_(printf_xml)( " </text>\n" );
+ } else {
+ count = VG_(vmessage)( Vg_ClientMsg, format, *vargsp );
+ VG_(message_flush)();
+ }
+
+ if (include_backtrace)
+ VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
+
+ if (VG_(clo_xml))
+ VG_(printf_xml)( "</clientmsg>\n" );
+
+ return count;
+}
+
+
/* Do a client request for the thread tid. After the request, tid may
or may not still be runnable; if not, the scheduler will have to
choose a new thread to run.
@@ -1708,6 +1778,7 @@
break;
case VG_USERREQ__PRINTF: {
+ const HChar* format = (HChar *)arg[1];
/* JRS 2010-Jan-28: this is DEPRECATED; use the
_VALIST_BY_REF version instead */
if (sizeof(va_list) != sizeof(UWord))
@@ -1718,13 +1789,14 @@
} u;
u.uw = (unsigned long)arg[2];
Int count =
- VG_(vmessage)( Vg_ClientMsg, (HChar *)arg[1], u.vargs );
- VG_(message_flush)();
+ print_client_message( tid, format, &u.vargs,
+ /* include_backtrace */ False );
SET_CLREQ_RETVAL( tid, count );
break;
}
case VG_USERREQ__PRINTF_BACKTRACE: {
+ const HChar* format = (HChar *)arg[1];
/* JRS 2010-Jan-28: this is DEPRECATED; use the
_VALIST_BY_REF version instead */
if (sizeof(va_list) != sizeof(UWord))
@@ -1735,28 +1807,29 @@
} u;
u.uw = (unsigned long)arg[2];
Int count =
- VG_(vmessage)( Vg_ClientMsg, (HChar *)arg[1], u.vargs );
- VG_(message_flush)();
- VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
+ print_client_message( tid, format, &u.vargs,
+ /* include_backtrace */ True );
SET_CLREQ_RETVAL( tid, count );
break;
}
case VG_USERREQ__PRINTF_VALIST_BY_REF: {
+ const HChar* format = (HChar *)arg[1];
va_list* vargsp = (va_list*)arg[2];
- Int count =
- VG_(vmessage)( Vg_ClientMsg, (HChar *)arg[1], *vargsp );
- VG_(message_flush)();
+ Int count =
+ print_client_message( tid, format, vargsp,
+ /* include_backtrace */ False );
+
SET_CLREQ_RETVAL( tid, count );
break;
}
case VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF: {
+ const HChar* format = (HChar *)arg[1];
va_list* vargsp = (va_list*)arg[2];
Int count =
- VG_(vmessage)( Vg_ClientMsg, (HChar *)arg[1], *vargsp );
- VG_(message_flush)();
- VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
+ print_client_message( tid, format, vargsp,
+ /* include_backtrace */ True );
SET_CLREQ_RETVAL( tid, count );
break;
}
diff --git a/docs/internals/xml-output-protocol4.txt b/docs/internals/xml-output-protocol4.txt
index 0dec54f..861d8ca 100644
--- a/docs/internals/xml-output-protocol4.txt
+++ b/docs/internals/xml-output-protocol4.txt
@@ -190,7 +190,7 @@
human-understandable. In current Valgrind versions it is the
elapsed wallclock time since process start.
-* Zero or more of (either ERRORCOUNTS or TOOLSPECIFIC).
+* Zero or more of (either ERRORCOUNTS, TOOLSPECIFIC, or CLIENTMSG).
* The following, indicating that the program has now finished, and
that the any final wrapup (eg, for Memcheck, leak checking) is happening.
@@ -699,3 +699,36 @@
One of various miscellaneous noteworthy conditions was observed
(eg, thread exited whilst holding locks, "impossible" behaviour
from the underlying threading library, etc)
+
+====================================================================
+
+CLIENTMSG
+
+CLIENTMSG defines a message that was caused by one of the following
+client requests:
+
+- VALGRIND_PRINTF
+- VALGRIND_PRINTF_BACKTRACE
+
+Definition:
+
+<clientmsg>
+ <tid>INT</tid>
+ <text>...</text>
+</clientmsg>
+
+OR
+
+<clientmsg>
+ <tid>INT</tid>
+ <text>...</text>
+ STACK
+</clientmsg>
+
+* The <tid> tag indicates the Valgrind thread number.
+
+* The <text> tag indicates the message as specified in the client request
+ (properly translated to XML).
+
+* STACK is only present in case of VALGRIND_PRINTF_BACKTRACE. See above
+ for a definition of STACK.
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index e363df4..2938133 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -74,6 +74,8 @@
buflen_check.stderr.exp-kfail \
bug287260.stderr.exp bug287260.vgtest \
calloc-overflow.stderr.exp calloc-overflow.vgtest\
+ client-msg.stderr.exp client-msg.vgtest \
+ client-msg-as-xml.stderr.exp client-msg-as-xml.vgtest \
clientperm.stderr.exp \
clientperm.stdout.exp clientperm.vgtest \
clireq_nofill.stderr.exp \
@@ -273,6 +275,7 @@
buflen_check \
bug287260 \
calloc-overflow \
+ client-msg \
clientperm \
clireq_nofill \
clo_redzone \
diff --git a/memcheck/tests/client-msg-as-xml.stderr.exp b/memcheck/tests/client-msg-as-xml.stderr.exp
new file mode 100644
index 0000000..af97c61
--- /dev/null
+++ b/memcheck/tests/client-msg-as-xml.stderr.exp
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+
+<valgrindoutput>
+
+<protocolversion>4</protocolversion>
+<protocoltool>memcheck</protocoltool>
+
+<preamble>
+ <line>...</line>
+ <line>...</line>
+ <line>...</line>
+ <line>...</line>
+</preamble>
+
+<pid>...</pid>
+<ppid>...</ppid>
+<tool>memcheck</tool>
+
+<args>
+ <vargv>...</vargv>
+ <argv>
+ <exe>./client-msg</exe>
+ </argv>
+</args>
+
+<status>
+ <state>RUNNING</state>
+ <time>...</time>
+</status>
+
+<clientmsg>
+ <tid>...</tid>
+ <text>hello <> <&>%s world
+ </text>
+ <stack>
+ <frame>
+ <ip>0x........</ip>
+ <obj>...</obj>
+ <fn>VALGRIND_PRINTF_BACKTRACE</fn>
+ <dir>...</dir>
+ <file>valgrind.h</file>
+ <line>...</line>
+ </frame>
+ <frame>
+ <ip>0x........</ip>
+ <obj>...</obj>
+ <fn>baz</fn>
+ <dir>...</dir>
+ <file>client-msg.c</file>
+ <line>...</line>
+ </frame>
+ <frame>
+ <ip>0x........</ip>
+ <obj>...</obj>
+ <fn>bar</fn>
+ <dir>...</dir>
+ <file>client-msg.c</file>
+ <line>...</line>
+ </frame>
+ <frame>
+ <ip>0x........</ip>
+ <obj>...</obj>
+ <fn>foo</fn>
+ <dir>...</dir>
+ <file>client-msg.c</file>
+ <line>...</line>
+ </frame>
+ <frame>
+ <ip>0x........</ip>
+ <obj>...</obj>
+ <fn>main</fn>
+ <dir>...</dir>
+ <file>client-msg.c</file>
+ <line>...</line>
+ </frame>
+ </stack>
+</clientmsg>
+
+<status>
+ <state>FINISHED</state>
+ <time>...</time>
+</status>
+
+<errorcounts>
+</errorcounts>
+
+<suppcounts>...</suppcounts>
+
+</valgrindoutput>
+
diff --git a/memcheck/tests/client-msg-as-xml.vgtest b/memcheck/tests/client-msg-as-xml.vgtest
new file mode 100644
index 0000000..b3e8121
--- /dev/null
+++ b/memcheck/tests/client-msg-as-xml.vgtest
@@ -0,0 +1,3 @@
+prog: client-msg
+vgopts: --xml=yes --xml-fd=2 --log-file=/dev/null
+stderr_filter: filter_xml
diff --git a/memcheck/tests/client-msg.c b/memcheck/tests/client-msg.c
new file mode 100644
index 0000000..cdcf43d
--- /dev/null
+++ b/memcheck/tests/client-msg.c
@@ -0,0 +1,24 @@
+#include "valgrind.h"
+
+void baz()
+{
+ VALGRIND_PRINTF_BACKTRACE("hello <> %s%%s world\n","<&>");
+}
+
+void bar()
+{
+ baz();
+}
+
+void foo()
+{
+ bar();
+}
+
+int main()
+{
+ foo();
+
+ return 0;
+}
+
diff --git a/memcheck/tests/client-msg.stderr.exp b/memcheck/tests/client-msg.stderr.exp
new file mode 100644
index 0000000..075d321
--- /dev/null
+++ b/memcheck/tests/client-msg.stderr.exp
@@ -0,0 +1,6 @@
+hello <> <&>%s world
+ ...
+ by 0x........: baz (client-msg.c:5)
+ by 0x........: bar (client-msg.c:10)
+ by 0x........: foo (client-msg.c:15)
+ by 0x........: main (client-msg.c:20)
diff --git a/memcheck/tests/client-msg.vgtest b/memcheck/tests/client-msg.vgtest
new file mode 100644
index 0000000..ace0364
--- /dev/null
+++ b/memcheck/tests/client-msg.vgtest
@@ -0,0 +1,2 @@
+prog: client-msg
+vgopts: -q