From e8f1ad9a8b8548dbc79c01b3df218ff2a97f1c05 Mon Sep 17 00:00:00 2001 From: Fred Fish Date: Wed, 24 Jan 1996 21:30:37 +0000 Subject: * NEWS: Make note of new record and replay feature for remote debug sessions. * serial.c (gdbcmd.h): Include. (serial_logfile, serial_logfp, serial_reading, serial_writing): Define here, for remote debug session logging. (serial_log_command, serial_logchar, serial_write, serial_readchar): New functions for remote debug session logging. (serial_open): Open remote debug session log file when needed. (serial_close): Close remote debug session log file when needed. (_initialize_serial): Add set/show commands for name of remote debug session log file. * serial.h (serial_readchar): Declare (SERIAL_READCHAR): Call serial_readchar(). (SERIAL_WRITE): Call serial_write(). (serial_close): Declare as extern. (serial_logfile, serial_logfp): Declare. * top.c (execute_command): Declare serial_logfp. Log user command in remote debug session log if log file is open. * remote-array.c (array_wait): #ifdef out echo to gdb_stdout. (array_read_inferior_memory): Rewrite to fix memory overwrite bug. * remote-array.c (SREC_SIZE): Remove, duplicates define in monitor.h. * remote-array.c (hexchars, hex2mem): Remove, unused. * gdbserver/low-linux.c (store_inferior_registers): Remove unnecessary extern declaration of registers[]. * gdbserver/Makefile.in (all): Add gdbreplay. * gdbserver/gdbreplay.c: New file. * gdbserver/README: Give example of recording a remote debug session with gdb and then replaying it with gdbreplay. --- gdb/serial.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) (limited to 'gdb/serial.c') diff --git a/gdb/serial.c b/gdb/serial.c index 72bfc50..c984d7a 100644 --- a/gdb/serial.c +++ b/gdb/serial.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "serial.h" #include "gdb_string.h" +#include "gdbcmd.h" /* Linked list of serial I/O handlers */ @@ -33,6 +34,110 @@ static serial_t last_serial_opened = NULL; static serial_t scb_base; +/* Non-NULL gives filename which contains a recording of the remote session, + suitable for playback by gdbserver. */ + +char *serial_logfile = NULL; +FILE *serial_logfp = NULL; + + +static int serial_reading = 0; +static int serial_writing = 0; + +void +serial_log_command (cmd) + const char *cmd; +{ + if (serial_reading || serial_writing) + { + fputc ('\n', serial_logfp); + serial_reading = 0; + serial_writing = 0; + } + fprintf (serial_logfp, "c %s\n", cmd); + /* Make sure that the log file is as up-to-date as possible, + in case we are getting ready to dump core or something. */ + fflush (serial_logfp); +} + +static void +serial_logchar (ch) + int ch; +{ + switch (ch) + { + case '\\': fputs ("\\\\", serial_logfp); break; + case '\b': fputs ("\\b", serial_logfp); break; + case '\f': fputs ("\\f", serial_logfp); break; + case '\n': fputs ("\\n", serial_logfp); break; + case '\r': fputs ("\\r", serial_logfp); break; + case '\t': fputs ("\\t", serial_logfp); break; + case '\v': fputs ("\\v", serial_logfp); break; + default: fprintf (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF); break; + } +} + +int +serial_write (scb, str, len) + serial_t scb; + const char *str; + int len; +{ + int count; + + if (serial_logfp != NULL) + { + if (serial_reading) + { + fputc ('\n', serial_logfp); + serial_reading = 0; + } + if (!serial_writing) + { + serial_logchar ('w'); + serial_logchar (' '); + serial_writing = 1; + } + for (count = 0; count < len; count++) + { + serial_logchar (str[count]); + } + /* Make sure that the log file is as up-to-date as possible, + in case we are getting ready to dump core or something. */ + fflush (serial_logfp); + } + return (scb -> ops -> write (scb, str, len)); +} + +int +serial_readchar (scb, timeout) + serial_t scb; + int timeout; +{ + int ch; + + ch = scb -> ops -> readchar (scb, timeout); + if (serial_logfp != NULL) + { + if (serial_writing) + { + fputc ('\n', serial_logfp); + serial_writing = 0; + } + if (!serial_reading) + { + serial_logchar ('r'); + serial_logchar (' '); + serial_reading = 1; + } + serial_logchar (ch); + /* Make sure that the log file is as up-to-date as possible, + in case we are getting ready to dump core or something. */ + fflush (serial_logfp); + } + return (ch); +} + static struct serial_ops * serial_interface_lookup (name) char *name; @@ -102,6 +207,15 @@ serial_open (name) last_serial_opened = scb; + if (serial_logfile != NULL) + { + serial_logfp = fopen (serial_logfile, "w"); + if (serial_logfp == NULL) + { + perror_with_name (serial_logfile); + } + } + return scb; } @@ -152,6 +266,18 @@ serial_close(scb, really_close) last_serial_opened = NULL; + if (serial_logfp) + { + if (serial_reading || serial_writing) + { + fputc ('\n', serial_logfp); + serial_reading = 0; + serial_writing = 0; + } + fclose (serial_logfp); + serial_logfp = NULL; + } + /* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you should fix your code instead. */ @@ -346,4 +472,12 @@ _initialize_serial () "Connect the terminal directly up to the command monitor.\n\ Use ~. or ~^D to break out."); #endif /* 0 */ + + add_show_from_set (add_set_cmd ("remotelogfile", no_class, + var_filename, (char *)&serial_logfile, + "Set filename for remote session recording.\n\ +This file is used to record the remote session for future playback\n\ +by gdbserver.", &setlist), + &showlist); + } -- cgit v1.1