- Addition of GDB server monitor command 'v.info open_fds' that gives the
list of open file descriptors and additional details.
+ - Optional message in the 'v.info n_errs_found' monitor command (e.g.
+ 'v.info n_errs_found test 1234 finished'), allowing to have
+ a comment string in the process output, separating errors of different
+ tests (or test phases).
+
- Addition of GDB server monitor command 'v.info execontext' that shows
information about the stack traces recorded by Valgrind.
This can be used to analyse one possible cause of Valgrind high
322851 0bXXX binary literal syntax is not standard
FIXED 2736
+324514 gdbserver monitor cmd output behaviour consistency + allow user
+ to put a "marker" msg in process log output
+ FIXED 13532
+
207815 Adds some of the drm ioctls to syswrap-linux.c
FIXED 13486
VG_(exit) (0);
}
+// s is a NULL terminated string made of O or more words (separated by spaces).
+// Returns a pointer to the Nth word in s.
+// If Nth word does not exist, return a pointer to the last (0) byte of s.
+static
+const char *wordn (const char *s, int n)
+{
+ int word_seen = 0;
+ Bool searching_word = True;
+
+ while (*s) {
+ if (*s == ' ')
+ searching_word = True;
+ else {
+ if (searching_word) {
+ searching_word = False;
+ word_seen++;
+ if (word_seen == n)
+ return s;
+ }
+ }
+ s++;
+ }
+ return s;
+}
+
/* handle_gdb_valgrind_command handles the provided mon string command.
If command is recognised, return 1 else return 0.
Note that in case of ambiguous command, 1 is returned.
'v.set *_output' is handled.
*/
static
-int handle_gdb_valgrind_command (char* mon, OutputSink* sink_wanted_at_return)
+int handle_gdb_valgrind_command (char *mon, OutputSink *sink_wanted_at_return)
{
UWord ret = 0;
char s[strlen(mon)+1]; /* copy for strtok_r */
- char* wcmd;
- HChar* ssaveptr;
- const char* endptr;
+ char *wcmd;
+ HChar *ssaveptr;
+ const char *endptr;
int kwdid;
int int_value;
" v.wait [<ms>] : sleep <ms> (default 0) then continue\n"
" v.info all_errors : show all errors found so far\n"
" v.info last_error : show last error found\n"
-" v.info n_errs_found : show the nr of errors found so far\n"
+" v.info n_errs_found [msg] : show the nr of errors found so far and the given msg\n"
" v.info open_fds : show open file descriptors (only if --track-fds=yes)\n"
" v.kill : kill the Valgrind process\n"
" v.set gdb_output : set valgrind output to gdb\n"
if (*endptr != '\0') {
VG_(gdb_printf) ("missing or malformed integer value\n");
} else if (kwdid == 0) {
- VG_(gdb_printf) ("vgdb-error value changed from %d to %d\n",
+ VG_(printf) ("vgdb-error value changed from %d to %d\n",
VG_(dyn_vgdb_error), int_value);
VG_(dyn_vgdb_error) = int_value;
} else if (kwdid == 1) {
- VG_(gdb_printf) ("debuglog value changed from %d to %d\n",
+ VG_(printf) ("debuglog value changed from %d to %d\n",
VG_(debugLog_getLevel)(), int_value);
VG_(debugLog_startup) (int_value, "gdbsrv");
} else if (kwdid == 2) {
- VG_(gdb_printf)
+ VG_(printf)
("merge-recursive-frames value changed from %d to %d\n",
VG_(clo_merge_recursive_frames), int_value);
VG_(clo_merge_recursive_frames) = int_value;
VG_(show_all_errors)(/* verbosity */ 2, /* xml */ False);
break;
case 1: // n_errs_found
- VG_(gdb_printf) ("n_errs_found %d n_errs_shown %d (vgdb-error %d)\n",
- VG_(get_n_errs_found) (),
- VG_(get_n_errs_shown) (),
- VG_(dyn_vgdb_error));
+ VG_(printf) ("n_errs_found %d n_errs_shown %d (vgdb-error %d) %s\n",
+ VG_(get_n_errs_found) (),
+ VG_(get_n_errs_shown) (),
+ VG_(dyn_vgdb_error),
+ wordn (mon, 3));
break;
case 2: // last_error
VG_(show_last_error)();
wcmd = strtok_r (NULL, " ", &ssaveptr);
if (wcmd != NULL) {
int_value = strtol (wcmd, NULL, 10);
- VG_(gdb_printf) ("gdbserver: continuing in %d ms ...\n", int_value);
+ VG_(printf) ("gdbserver: continuing in %d ms ...\n", int_value);
VG_(poll)(NULL, 0, int_value);
}
- VG_(gdb_printf) ("gdbserver: continuing after wait ...\n");
+ VG_(printf) ("gdbserver: continuing after wait ...\n");
ret = 1;
break;
case 4: /* v.kill */
Note that in case of ambiguous command, 1 is returned.
*/
static
-int handle_gdb_monitor_command (char* mon)
+int handle_gdb_monitor_command (char *mon)
{
UWord ret = 0;
UWord tool_ret = 0;
VG_(dyn_vgdb_error) = save_dyn_vgdb_error;
}
+ VG_(message_flush) ();
+
/* restore or set the desired output */
VG_(log_output_sink).fd = sink_wanted_at_return.fd;
if (ret | tool_ret)
arg_own_buf[0] = 0;
}
-Bool VG_(client_monitor_command) (HChar* cmd)
+Bool VG_(client_monitor_command) (HChar *cmd)
{
const Bool connected = remote_connected();
const int saved_command_output_to_log = command_output_to_log;
cmd[cmdlen] = '\0';
if (handle_gdb_monitor_command (cmd)) {
- /* In case the command is from a standalone vgdb,
- connection will be closed soon => flush the output. */
- VG_(message_flush) ();
write_ok (arg_own_buf);
return;
} else {
any more output. */
if (sink->fd >= 0)
VG_(write)( sink->fd, msg, nbytes );
- else if (sink->fd == -2)
+ else if (sink->fd == -2 && nbytes > 0)
+ /* send to gdb the provided data, which must be
+ a null terminated string with len >= 1 */
VG_(gdb_printf)("%s", msg);
}
}
argument values) that can match:
<programlisting><![CDATA[
(gdb) mo v. n
-v. can match v.set v.info v.wait v.kill v.translate
+v. can match v.set v.info v.wait v.kill v.translate v.do
(gdb) mo v.i n
n_errs_found 0 n_errs_shown 0 (vgdb-error 0)
(gdb)
</listitem>
<listitem>
- <para><varname>v.info n_errs_found</varname> shows the number of
+ <para><varname>v.info n_errs_found [msg]</varname> shows the number of
errors found so far, the nr of errors shown so far and the current
- value of the <option>--vgdb-error</option> argument.</para>
+ value of the <option>--vgdb-error</option> argument. The optional
+ <computeroutput>msg</computeroutput> (one or more words) is appended.
+ Typically, this can be used to insert markers in a process output
+ file between several tests executed in sequence by a process
+ started only once. This allows to associate the errors reported
+ by Valgrind with the specific test that produced these errors.
+ </para>
</listitem>
<listitem>
relaying data between gdb and process ....
vgdb-error value changed from 0 to 999999
vgdb-error value changed from 999999 to 0
-n_errs_found 1 n_errs_shown 1 (vgdb-error 0)
+n_errs_found 1 n_errs_shown 1 (vgdb-error 0)
+n_errs_found 1 n_errs_shown 1 (vgdb-error 0) a
+n_errs_found 1 n_errs_shown 1 (vgdb-error 0) b
+n_errs_found 1 n_errs_shown 1 (vgdb-error 0) c d
+n_errs_found 1 n_errs_shown 1 (vgdb-error 0) eeeeeee fffffff ggggggg
vgdb-error value changed from 0 to 0
monitor command request to kill this process
Remote connection closed
delete
continue
monitor v.info n_errs_found
+monitor v.info n_errs_found a
+monitor v.info n_errs_found b
+monitor v.info n_errs_found c d
+monitor v.info n_errs_found eeeeeee fffffff ggggggg
# inferior call "in the middle" of an instruction is not working at least
# on all platforms, so comment the below.
# print whoami("after error: inferior call pushed from mcbreak.stdinB.gdb")
v.wait [<ms>] : sleep <ms> (default 0) then continue
v.info all_errors : show all errors found so far
v.info last_error : show last error found
- v.info n_errs_found : show the nr of errors found so far
+ v.info n_errs_found [msg] : show the nr of errors found so far and the given msg
v.info open_fds : show open file descriptors (only if --track-fds=yes)
v.kill : kill the Valgrind process
v.set gdb_output : set valgrind output to gdb
v.wait [<ms>] : sleep <ms> (default 0) then continue
v.info all_errors : show all errors found so far
v.info last_error : show last error found
- v.info n_errs_found : show the nr of errors found so far
+ v.info n_errs_found [msg] : show the nr of errors found so far and the given msg
v.info open_fds : show open file descriptors (only if --track-fds=yes)
v.kill : kill the Valgrind process
v.set gdb_output : set valgrind output to gdb
v.wait [<ms>] : sleep <ms> (default 0) then continue
v.info all_errors : show all errors found so far
v.info last_error : show last error found
- v.info n_errs_found : show the nr of errors found so far
+ v.info n_errs_found [msg] : show the nr of errors found so far and the given msg
v.info open_fds : show open file descriptors (only if --track-fds=yes)
v.kill : kill the Valgrind process
v.set gdb_output : set valgrind output to gdb
// can be used during the processing of the VG_USERREQ__GDB_MONITOR_COMMAND
// tool client request to output information to gdb or vgdb.
+// The output of VG_(gdb_printf) is not subject to 'output control'
+// by the user: e.g. the monitor command 'v.set log_output' has no effect.
+// The output of VG_(gdb_printf) is given to gdb/vgdb. The only case
+// in which this output is not given to gdb/vgdb is when the connection
+// with gdb/vgdb has been lost : in such a case, output is written
+// to the valgrind log output.
+// To produce some output which is subject to user output control via
+// monitor command v.set gdb_output or mixed output, use VG_(printf)
+// or VG_(umsg) or similar.
+// Typically, VG_(gdb_printf) has to be used when there is no point
+// having this output in the output log of Valgrind. Examples
+// is the monitor help output, or if vgdb is used to implement
+// 'tool control scripts' such as callgrind_control.
extern UInt VG_(gdb_printf) ( const HChar *format, ... ) PRINTF_CHECK(1, 2);
/* Utility functions to (e.g.) parse gdb monitor commands.
False /* is client request */ );
/* we are before the first character on next line, print a \n. */
if ((i % 32) == 0 && i != 0)
- VG_(gdb_printf) ("\n");
+ VG_(printf) ("\n");
/* we are before the next block of 4 starts, print a space. */
else if ((i % 4) == 0 && i != 0)
- VG_(gdb_printf) (" ");
+ VG_(printf) (" ");
if (res == 1) {
- VG_(gdb_printf) ("%02x", vbits);
+ VG_(printf) ("%02x", vbits);
} else {
tl_assert(3 == res);
unaddressable++;
- VG_(gdb_printf) ("__");
+ VG_(printf) ("__");
}
}
- VG_(gdb_printf) ("\n");
+ VG_(printf) ("\n");
if (unaddressable) {
- VG_(gdb_printf)
+ VG_(printf)
("Address %p len %ld has %d bytes unaddressable\n",
(void *)address, szB, unaddressable);
}
case -1: break;
case 0:
if (is_mem_addressable ( address, szB, &bad_addr ))
- VG_(gdb_printf) ("Address %p len %ld addressable\n",
+ VG_(printf) ("Address %p len %ld addressable\n",
(void *)address, szB);
else
- VG_(gdb_printf)
+ VG_(printf)
("Address %p len %ld not addressable:\nbad address %p\n",
(void *)address, szB, (void *) bad_addr);
MC_(pp_describe_addr) (address);
break;
case 1: res = is_mem_defined ( address, szB, &bad_addr, &otag );
if (MC_AddrErr == res)
- VG_(gdb_printf)
+ VG_(printf)
("Address %p len %ld not addressable:\nbad address %p\n",
(void *)address, szB, (void *) bad_addr);
else if (MC_ValueErr == res) {
src = ""; break;
default: tl_assert(0);
}
- VG_(gdb_printf)
+ VG_(printf)
("Address %p len %ld not defined:\n"
"Uninitialised value at %p%s\n",
(void *)address, szB, (void *) bad_addr, src);
}
}
else
- VG_(gdb_printf) ("Address %p len %ld defined\n",
- (void *)address, szB);
+ VG_(printf) ("Address %p len %ld defined\n",
+ (void *)address, szB);
MC_(pp_describe_addr) (address);
break;
default: tl_assert(0);