Also cleanup some trailink blanks.
* New and modified GDB server monitor features:
+ - Option -T tells vgdb to output a timestamp in the vgdb information messages.
+
- The gdbserver monitor commands that require an address and an optional
length argument now accepts the alternate 'C like' syntax "address[length]".
For example, the memcheck command "monitor who_points_at 0x12345678 120"
void invoker_restrictions_msg(void)
{
- fprintf(stderr,
- "Note: vgdb invoker not implemented on this platform.\n"
- "For more info: read user manual section"
- " 'Limitations of the Valgrind gdbserver'.\n");
+ TSFPRINTF(stderr,
+ "Note: vgdb invoker not implemented on this platform.\n"
+ "For more info: read user manual section"
+ " 'Limitations of the Valgrind gdbserver'.\n");
}
void invoker_cleanup_restore_and_detach(void *v_pid)
/* Allocate buffer of that many longwords. */
register PTRACE_XFER_TYPE *buffer
= (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
-
+
/* Read all the longwords */
for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) {
errno = 0;
- buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
+ buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
(PTRACE_ARG3_TYPE) addr, 0);
if (errno)
return errno;
}
-
+
/* Copy appropriate bytes out of the buffer. */
- memcpy (myaddr,
+ memcpy (myaddr,
(char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len);
-
+
return 0;
}
returns the value of errno. */
__attribute__((unused)) /* not used on all platforms */
static
-int ptrace_write_memory (pid_t inferior_pid, CORE_ADDR memaddr,
+int ptrace_write_memory (pid_t inferior_pid, CORE_ADDR memaddr,
const void *myaddr, size_t len)
{
register int i;
register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
/* Round ending address up; get number of longwords that makes. */
register int count
- = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
+ = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
/ sizeof (PTRACE_XFER_TYPE);
/* Allocate buffer of that many longwords. */
- register PTRACE_XFER_TYPE *buffer
+ register PTRACE_XFER_TYPE *buffer
= (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
-
+
if (debuglevel >= 1) {
DEBUG (1, "Writing ");
for (i = 0; i < len; i++)
PDEBUG (1, "%02x", ((const unsigned char*)myaddr)[i]);
PDEBUG(1, " to %p\n", (void *) memaddr);
}
-
+
/* Fill start and end extra bytes of buffer with existing memory data. */
-
+
buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
(PTRACE_ARG3_TYPE) addr, 0);
-
+
if (count > 1) {
buffer[count - 1]
= ptrace (PTRACE_PEEKTEXT, inferior_pid,
* sizeof (PTRACE_XFER_TYPE)),
0);
}
-
+
/* Copy data to be written over corresponding part of buffer */
-
- memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
+
+ memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
myaddr, len);
-
+
/* Write the entire buffer. */
-
+
for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) {
errno = 0;
- ptrace (PTRACE_POKETEXT, inferior_pid,
+ ptrace (PTRACE_POKETEXT, inferior_pid,
(PTRACE_ARG3_TYPE) addr, buffer[i]);
if (errno)
return errno;
}
-
+
return 0;
}
}
}
-static
+static
char *status_image (int status)
{
static char result[256]; // large enough
int sz = 0;
#define APPEND(...) sz += snprintf (result+sz, 256 - sz - 1, __VA_ARGS__)
-
+
result[0] = 0;
if (WIFEXITED(status))
APPEND ("WIFEXITED %d ", WEXITSTATUS(status));
-
+
if (WIFSIGNALED(status)) {
APPEND ("WIFSIGNALED %d ", WTERMSIG(status));
if (WCOREDUMP(status)) APPEND ("WCOREDUMP ");
DEBUG(1, "waitstopped %s before waitpid signal_expected %d\n",
msg, signal_expected);
p = waitpid(pid, &status, __WALL);
- DEBUG(1, "after waitpid pid %d p %d status 0x%x %s\n", pid, p,
+ DEBUG(1, "after waitpid pid %d p %d status 0x%x %s\n", pid, p,
status, status_image (status));
if (p != pid) {
- ERROR(errno, "%s waitpid pid %d in waitstopped %d status 0x%x %s\n",
+ ERROR(errno, "%s waitpid pid %d in waitstopped %d status 0x%x %s\n",
msg, pid, p, status, status_image (status));
return False;
}
// realloc a bigger queue, and store new signal at the end.
// This is not very efficient but we assume not many sigs are queued.
signal_queue_sz++;
- signal_queue = vrealloc(signal_queue,
+ signal_queue = vrealloc(signal_queue,
sizeof(siginfo_t) * signal_queue_sz);
newsiginfo = signal_queue + (signal_queue_sz - 1);
ERROR(errno, "%s SIGSTOP pid %d %ld\n", msg, pid, res);
return False;
}
-
+
return waitstopped (pid, SIGSTOP, msg);
}
long res;
static Bool output_error = True;
static Bool initial_attach = True;
- // For a ptrace_scope protected system, we do not want to output
+ // For a ptrace_scope protected system, we do not want to output
// repetitively attach error. We will output once an error
// for the initial_attach. Once the 1st attach has succeeded, we
// again show all errors.
return waitstopped(pid, SIGSTOP, msg);
}
-/* once we are attached to the pid, get the list of threads and stop
+/* once we are attached to the pid, get the list of threads and stop
them all.
Returns True if all threads properly suspended, False otherwise. */
static
ERROR(rw, "status ptrace_read_memory\n");
return False;
}
-
+
rw = ptrace_read_memory(pid, vgt+off_lwpid,
&(vgdb_threads[i].lwpid),
sizeof(Int));
ERROR(rw, "lwpid ptrace_read_memory\n");
return False;
}
-
+
if (vgdb_threads[i].status != VgTs_Empty) {
DEBUG(1, "found tid %d status %s lwpid %d\n",
i, name_of_ThreadStatus(vgdb_threads[i].status),
vgdb_threads[i].lwpid);
nr_live_threads++;
if (vgdb_threads[i].lwpid <= 1) {
- if (vgdb_threads[i].lwpid == 0
+ if (vgdb_threads[i].lwpid == 0
&& vgdb_threads[i].status == VgTs_Init) {
DEBUG(1, "not set lwpid tid %d status %s lwpid %d\n",
i, name_of_ThreadStatus(vgdb_threads[i].status),
pid_found = True;
} else {
if (!attach(vgdb_threads[i].lwpid, "attach_thread")) {
- ERROR(0, "ERROR attach pid %d tid %d\n",
+ ERROR(0, "ERROR attach pid %d tid %d\n",
vgdb_threads[i].lwpid, i);
return False;
}
if (vgdb_threads[i].status == VgTs_Init
&& vgdb_threads[i].lwpid == 0) {
DEBUG(1, "skipping PTRACE_DETACH pid %d tid %d status %s\n",
- vgdb_threads[i].lwpid, i,
+ vgdb_threads[i].lwpid, i,
name_of_ThreadStatus (vgdb_threads[i].status));
} else {
if (vgdb_threads[i].lwpid == pid) {
pid_found = True;
}
DEBUG(1, "PTRACE_DETACH pid %d tid %d status %s\n",
- vgdb_threads[i].lwpid, i,
+ vgdb_threads[i].lwpid, i,
name_of_ThreadStatus (vgdb_threads[i].status));
res = ptrace (PTRACE_DETACH, vgdb_threads[i].lwpid, NULL, NULL);
if (res != 0) {
- ERROR(errno, "PTRACE_DETACH pid %d tid %d status %s res %ld\n",
+ ERROR(errno, "PTRACE_DETACH pid %d tid %d status %s res %ld\n",
vgdb_threads[i].lwpid, i,
name_of_ThreadStatus (vgdb_threads[i].status),
res);
#endif
/* Get the registers from pid into regs.
- regs_bsz value gives the length of *regs.
+ regs_bsz value gives the length of *regs.
Returns True if all ok, otherwise False. */
static
Bool getregs (pid_t pid, void *regs, long regs_bsz)
}
/* Set the registers of pid to regs.
- regs_bsz value gives the length of *regs.
+ regs_bsz value gives the length of *regs.
Returns True if all ok, otherwise False. */
static
Bool setregs (pid_t pid, void *regs, long regs_bsz)
sp = sp - regsize;
DEBUG(1, "push check arg ptrace_write_memory\n");
assert(regsize == sizeof(check));
- rw = ptrace_write_memory(pid, sp,
- &check,
+ rw = ptrace_write_memory(pid, sp,
+ &check,
regsize);
if (rw != 0) {
ERROR(rw, "push check arg ptrace_write_memory");
DEBUG(1, "push bad_return return address ptrace_write_memory\n");
// Note that for a 64 bits vgdb, only 4 bytes of NULL bad_return
// are written.
- rw = ptrace_write_memory(pid, sp,
+ rw = ptrace_write_memory(pid, sp,
&bad_return,
regsize);
if (rw != 0) {
else {
assert(0);
}
-
+
if (!setregs(pid, &user_mod.regs, sizeof(user_mod.regs))) {
detach_from_all_threads(pid);
return False;
must restore the registers in case of cleanup. */
pid_of_save_regs = pid;
pid_of_save_regs_continued = False;
-
- /* We PTRACE_CONT-inue pid.
+
+ /* We PTRACE_CONT-inue pid.
Either gdbserver will be invoked directly (if all
threads are interruptible) or gdbserver will be
called soon by the scheduler. In the first case,
*/
int debuglevel;
-struct timeval dbgtv;
+Bool timestamp = False;
+char timestamp_out[20];
static char *vgdb_prefix = NULL;
+char *timestamp_str (Bool produce)
+{
+ static char out[50];
+ char *ptr;
+ struct timeval dbgtv;
+ struct tm *ts_tm;
+
+ if (produce) {
+ gettimeofday(&dbgtv, NULL);
+ ts_tm = localtime(&dbgtv.tv_sec);
+ ptr = out + strftime(out, sizeof(out), "%H:%M:%S", ts_tm);
+ sprintf(ptr, ".%6.6ld ", dbgtv.tv_usec);
+ } else {
+ out[0] = 0;
+ }
+ return out;
+}
+
/* Will be set to True when any condition indicating we have to shutdown
is encountered. */
Bool shutting_down = False;
if (-1 == bind(listen_gdb, (struct sockaddr *)&addr, sizeof(addr))) {
XERROR(errno, "bind failed");
}
- fprintf(stderr, "listening on port %d ...", in_port);
- fflush(stderr);
+ TSFPRINTF(stderr, "listening on port %d ...", in_port);
if (-1 == listen(listen_gdb, 1)) {
XERROR(errno, "error listen failed");
}
if (bufcnt <= 0) {
if (bufcnt == 0) {
- fprintf(stderr, "readchar: Got EOF\n");
+ TSFPRINTF(stderr, "readchar: Got EOF\n");
return -2;
} else {
ERROR(errno, "readchar\n");
if (csum == (c1 << 4) + c2)
break;
- fprintf(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
- (c1 << 4) + c2, csum, buf);
+ TSFPRINTF(stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
+ (c1 << 4) + c2, csum, buf);
if (write(ackfd, "-", 1) != 1)
ERROR(0, "error when writing - (nack)\n");
else
int to_pid = -1; /* fd to write to pid */
int shutdown_loop = 0;
- fprintf(stderr, "relaying data between gdb and process %d\n", pid);
- fflush(stderr);
+ TSFPRINTF(stderr, "relaying data between gdb and process %d\n", pid);
if (max_invoke_ms > 0)
pthread_create(&invoke_gdbserver_in_valgrind_thread, NULL,
}
for (nc = 0; nc <= last_command; nc++) {
- fprintf(stderr, "sending command %s to pid %d\n", commands[nc], pid);
- fflush(stderr);
+ TSFPRINTF(stderr, "sending command %s to pid %d\n", commands[nc], pid);
/* prepare hexcommand $qRcmd,xxxx....................xx#cc */
hexcommand = vmalloc(packet_len_for_command(commands[nc]));
int fd, i;
FILE *out = on_stdout ? stdout : stderr;
- fprintf(out, "use --pid=%d for ", pid);
+ TSFPRINTF(out, "use --pid=%d for ", pid);
sprintf(cmdline_file, "/proc/%d/cmdline", pid);
fd = open(cmdline_file, O_RDONLY);
" OPTIONS are [--pid=<number>] [--vgdb-prefix=<prefix>]\n"
" [--wait=<number>] [--max-invoke-ms=<number>]\n"
" [--port=<portnr>\n"
-" [--cmd-time-out=<number>] [-l] [-D] [-d]\n"
+" [--cmd-time-out=<number>] [-l] [-T] [-D] [-d]\n"
" \n"
" --pid arg must be given if multiple Valgrind gdbservers are found.\n"
" --vgdb-prefix arg must be given to both Valgrind and vgdb utility\n"
" --cmd-time-out (default 99999999) tells vgdb to exit if the found Valgrind\n"
" gdbserver has not processed a command after number seconds\n"
" -l arg tells to show the list of running Valgrind gdbserver and then exit.\n"
+" -T arg tells to add timestamps to vgdb information messages.\n"
" -D arg tells to show shared mem status and then exit.\n"
" -d arg tells to show debug info. Multiple -d args for more debug info\n"
"\n"
int pid = -1;
if (arg_pid == 0 || arg_pid < -1) {
- fprintf(stderr, "vgdb error: invalid pid %d given\n", arg_pid);
+ TSFPRINTF(stderr, "vgdb error: invalid pid %d given\n", arg_pid);
exit(1);
} else {
/* search for a matching named fifo.
}
} else if (nr_valid_pid > 1) {
if (nr_valid_pid == 2) {
- fprintf
+ TSFPRINTF
(stderr,
"no --pid= arg given"
" and multiple valgrind pids found:\n");
exit(1);
} else if (pid == -1) {
if (arg_pid == -1)
- fprintf(stderr, "vgdb error: no FIFO found and no pid given\n");
+ TSFPRINTF(stderr, "vgdb error: no FIFO found and no pid given\n");
else
- fprintf(stderr, "vgdb error: no FIFO found matching pid %d\n",
- arg_pid);
+ TSFPRINTF(stderr, "vgdb error: no FIFO found matching pid %d\n",
+ arg_pid);
exit(1);
}
else if (pid == -2) {
show_shared_mem = True;
} else if (is_opt(argv[i], "-l")) {
show_list = True;
+ } else if (is_opt(argv[i], "-T")) {
+ timestamp = True;
} else if (is_opt(argv[i], "--pid=")) {
int newpid;
if (!numeric_val(argv[i], &newpid)) {
- fprintf(stderr, "invalid --pid argument %s\n", argv[i]);
+ TSFPRINTF(stderr, "invalid --pid argument %s\n", argv[i]);
arg_errors++;
} else if (arg_pid != -1) {
- fprintf(stderr, "multiple --pid arguments given\n");
+ TSFPRINTF(stderr, "multiple --pid arguments given\n");
arg_errors++;
} else {
arg_pid = newpid;
}
} else if (is_opt(argv[i], "--wait=")) {
if (!numeric_val(argv[i], &check_trials)) {
- fprintf(stderr, "invalid --wait argument %s\n", argv[i]);
+ TSFPRINTF(stderr, "invalid --wait argument %s\n", argv[i]);
arg_errors++;
}
} else if (is_opt(argv[i], "--max-invoke-ms=")) {
if (!numeric_val(argv[i], &max_invoke_ms)) {
- fprintf(stderr, "invalid --max-invoke-ms argument %s\n", argv[i]);
+ TSFPRINTF(stderr, "invalid --max-invoke-ms argument %s\n", argv[i]);
arg_errors++;
}
} else if (is_opt(argv[i], "--cmd-time-out=")) {
if (!numeric_val(argv[i], &cmd_time_out)) {
- fprintf(stderr, "invalid --cmd-time-out argument %s\n", argv[i]);
+ TSFPRINTF(stderr, "invalid --cmd-time-out argument %s\n", argv[i]);
arg_errors++;
}
} else if (is_opt(argv[i], "--port=")) {
if (!numeric_val(argv[i], &int_port)) {
- fprintf(stderr, "invalid --port argument %s\n", argv[i]);
+ TSFPRINTF(stderr, "invalid --port argument %s\n", argv[i]);
arg_errors++;
}
} else if (is_opt(argv[i], "--vgdb-prefix=")) {
commands[last_command] = vmalloc(1);
commands[last_command][0] = '\0';
} else if (0 == strncmp(argv[i], "-", 1)) {
- fprintf(stderr, "unknown or invalid argument %s\n", argv[i]);
+ TSFPRINTF(stderr, "unknown or invalid argument %s\n", argv[i]);
arg_errors++;
} else {
int len;
strcat(commands[last_command], " ");
strcat(commands[last_command], argv[i]);
if (packet_len_for_command(commands[last_command]) > PBUFSIZ) {
- fprintf(stderr, "command %s too long\n", commands[last_command]);
+ TSFPRINTF(stderr, "command %s too long\n", commands[last_command]);
arg_errors++;
}
&& int_port == 0
&& last_command == -1) {
arg_errors++;
- fprintf(stderr,
- "Using vgdb standalone implies to give -D or -l or a COMMAND\n");
+ TSFPRINTF(stderr,
+ "Using vgdb standalone implies to give -D or -l or a COMMAND\n");
}
if (show_shared_mem && show_list) {
arg_errors++;
- fprintf(stderr,
- "Can't use both -D and -l options\n");
+ TSFPRINTF(stderr,
+ "Can't use both -D and -l options\n");
}
if (max_invoke_ms > 0
&& cmd_time_out != NEVER
&& (cmd_time_out * 1000) <= max_invoke_ms) {
arg_errors++;
- fprintf(stderr,
- "--max-invoke-ms must be < --cmd-time-out * 1000\n");
+ TSFPRINTF(stderr,
+ "--max-invoke-ms must be < --cmd-time-out * 1000\n");
}
if (show_list && arg_pid != -1) {
arg_errors++;
- fprintf(stderr,
- "Can't use both --pid and -l options\n");
+ TSFPRINTF(stderr,
+ "Can't use both --pid and -l options\n");
}
if (int_port > 0 && last_command != -1) {
arg_errors++;
- fprintf(stderr,
- "Can't use --port to send commands\n");
+ TSFPRINTF(stderr,
+ "Can't use --port to send commands\n");
}
if (arg_errors > 0) {
- fprintf(stderr, "args error. Try `vgdb --help` for more information\n");
+ TSFPRINTF(stderr, "args error. Try `vgdb --help` for more information\n");
exit(1);
}
wait_for_gdb_connect(in_port);
if (show_shared_mem) {
- fprintf(stderr,
- "vgdb %d "
- "written_by_vgdb %d "
- "seen_by_valgrind %d\n"
- "vgdb pid %d\n",
- VS_vgdb_pid,
- VS_written_by_vgdb,
- VS_seen_by_valgrind,
- VS_vgdb_pid);
+ TSFPRINTF(stderr,
+ "vgdb %d "
+ "written_by_vgdb %d "
+ "seen_by_valgrind %d\n",
+ VS_vgdb_pid,
+ VS_written_by_vgdb,
+ VS_seen_by_valgrind);
+ TSFPRINTF(stderr, "vgdb pid %d\n", VS_vgdb_pid);
exit(0);
}
#include <sys/types.h>
+extern Bool timestamp;
+extern char *timestamp_str (Bool produce);
extern int debuglevel;
-extern struct timeval dbgtv;
-/* if level <= debuglevel, print timestamp, then print provided by debug info */
+
+/* Optionally prints a timestamp, then prints the given info. This should
+ be used only at the beginning of a new line. */
+#define TSFPRINTF(stream, ...) ( \
+ fprintf(stream, "%s", timestamp_str(timestamp)), \
+ fprintf(stream, __VA_ARGS__),fflush(stream))
+
+/* if level <= debuglevel, print timestamp, then prints provided debug info */
#define DEBUG(level, ...) (level <= debuglevel ? \
- gettimeofday(&dbgtv, NULL), \
- fprintf(stderr, "%ld.%6.6ld ", \
- (long int)dbgtv.tv_sec, \
- (long int)dbgtv.tv_usec), \
+ fprintf(stderr, "%s", timestamp_str(True)), \
fprintf(stderr, __VA_ARGS__),fflush(stderr) \
: 0)
fprintf(stderr, __VA_ARGS__),fflush(stderr) \
: 0)
-/* if errno != 0,
+/* if errno != 0,
report the errno and fprintf the ... varargs on stderr. */
#define ERROR(errno, ...) ((errno == 0 ? 0 : perror("syscall failed")), \
+ fprintf(stderr, "%s", timestamp_str(timestamp)), \
fprintf(stderr, __VA_ARGS__), \
fflush(stderr))
/* same as ERROR, but also exits with status 1 */
#define XERROR(errno, ...) ((errno == 0 ? 0 : perror("syscall failed")), \
- fprintf(stderr, __VA_ARGS__), \
- fflush(stderr), \
+ fprintf(stderr, "%s", timestamp_str(timestamp)), \
+ fprintf(stderr, __VA_ARGS__), \
+ fflush(stderr), \
exit(1))
/* Calls malloc (size). Exits if memory can't be allocated. */
exit.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>-T</option></term>
+ <listitem><para>Instructs vgdb to add timestamps to vgdb
+ information messages.
+ </para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>-D</option></term>
<listitem><para>Instructs a standalone vgdb to show the