diff --git a/NEWS b/NEWS
index 76939f814..d5770a564 100644
--- a/NEWS
+++ b/NEWS
@@ -443,6 +443,9 @@ FIXED r??
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 eb3351e11..b20ab919a 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -1654,6 +1654,76 @@ static Bool os_client_request(ThreadId tid, UWord *args)
}
+/* 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)( "\n" );
+ VG_(printf_xml)( " %d\n", tid );
+ VG_(printf_xml)( " " );
+ count = VG_(vprintf_xml)( xml_format, *vargsp );
+ VG_(printf_xml)( " \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)( "\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 @@ void do_client_request ( ThreadId tid )
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 @@ void do_client_request ( ThreadId tid )
} 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 @@ void do_client_request ( ThreadId tid )
} 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 0dec54fae..861d8ca21 100644
--- a/docs/internals/xml-output-protocol4.txt
+++ b/docs/internals/xml-output-protocol4.txt
@@ -190,7 +190,7 @@ the following in sequence:
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 @@ The possible values are:
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:
+
+
+ INT
+ ...
+
+
+OR
+
+
+ INT
+ ...
+ STACK
+
+
+* The tag indicates the Valgrind thread number.
+
+* The 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 e363df48e..293813323 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -74,6 +74,8 @@ EXTRA_DIST = \
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 @@ check_PROGRAMS = \
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 000000000..af97c61ab
--- /dev/null
+++ b/memcheck/tests/client-msg-as-xml.stderr.exp
@@ -0,0 +1,90 @@
+
+
+
+
+4
+memcheck
+
+
+ ...
+ ...
+ ...
+ ...
+
+
+...
+...
+memcheck
+
+
+ ...
+
+ ./client-msg
+
+
+
+
+ RUNNING
+
+
+
+
+ ...
+ hello <> <&>%s world
+
+
+
+ 0x........
+ ...
+ VALGRIND_PRINTF_BACKTRACE
+ ...
+ valgrind.h
+ ...
+
+
+ 0x........
+ ...
+ baz
+ ...
+ client-msg.c
+ ...
+
+
+ 0x........
+ ...
+ bar
+ ...
+ client-msg.c
+ ...
+
+
+ 0x........
+ ...
+ foo
+ ...
+ client-msg.c
+ ...
+
+
+ 0x........
+ ...
+ main
+ ...
+ client-msg.c
+ ...
+
+
+
+
+
+ FINISHED
+
+
+
+
+
+
+...
+
+
+
diff --git a/memcheck/tests/client-msg-as-xml.vgtest b/memcheck/tests/client-msg-as-xml.vgtest
new file mode 100644
index 000000000..b3e812170
--- /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 000000000..cdcf43d10
--- /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 000000000..075d32161
--- /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 000000000..ace036469
--- /dev/null
+++ b/memcheck/tests/client-msg.vgtest
@@ -0,0 +1,2 @@
+prog: client-msg
+vgopts: -q