* NEWS: Make note of new record and replay feature for
authorFred Fish <fnf@specifix.com>
Wed, 24 Jan 1996 21:30:37 +0000 (21:30 +0000)
committerFred Fish <fnf@specifix.com>
Wed, 24 Jan 1996 21:30:37 +0000 (21:30 +0000)
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/ChangeLog
gdb/NEWS
gdb/gdbserver/gdbreplay.c [new file with mode: 0644]
gdb/gdbserver/low-linux.c
gdb/remote-array.c
gdb/serial.c
gdb/serial.h
gdb/top.c

index 69faad22039b76c4e89e3a4bdc6fa05c73ae65b2..1cbdf9b0543951aab48bd8485add38f205aa44aa 100644 (file)
@@ -1,3 +1,35 @@
+Wed Jan 24 13:19:10 1996  Fred Fish  <fnf@cygnus.com>
+
+       * 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.
+       
 Tue Jan 23 18:02:35 1996  Per Bothner  <bothner@kalessin.cygnus.com>
 
        * stabsread.c (rs6000_builtin_type):  Make bool type unsigned.
index 0867bde4c7849434a64507dd1bea7cf6dca1d545..813b60aafbd0d4e1bcfcd7a8d6bba2bbcb40ad6d 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -32,6 +32,16 @@ Note this feature does not work on hpux8.  On hpux9 you must link
 /usr/lib/end.o into your program.  This feature should work automatically
 on hpux10.
 
+* Recording and replaying remote debug sessions
+
+If you set "remotelogfile" gdb will use that filename to make a
+"recording" of a remote debug session which can be replayed back to
+gdb using "gdbreplay".  See gdbserver/README for details.  This is
+useful when you have a problem with gdb while doing remote debugging.
+By making a recording of the session and sending it to the gdb
+maintainers, it is possible to recreate your problem without access to
+the remote hardware you are using.
+
 *** Changes in GDB-4.15:
 
 * Psymtabs for XCOFF
diff --git a/gdb/gdbserver/gdbreplay.c b/gdb/gdbserver/gdbreplay.c
new file mode 100644 (file)
index 0000000..4d5795a
--- /dev/null
@@ -0,0 +1,319 @@
+/* Replay a remote debug session logfile for GDB.
+   Copyright (C) 1996 Free Software Foundation, Inc.
+   Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include <stdio.h>
+#include <sgtty.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <ctype.h>
+
+/* Sort of a hack... */
+#define EOL (EOF - 1)
+
+static int remote_desc;
+
+/* Print the system error message for errno, and also mention STRING
+   as the file name for which the error was encountered.
+   Then return to command level.  */
+
+void
+perror_with_name (string)
+     char *string;
+{
+  extern int sys_nerr;
+  extern char *sys_errlist[];
+  extern int errno;
+  char *err;
+  char *combined;
+
+  err = (errno < sys_nerr) ? sys_errlist[errno] : "unknown error";
+  combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+  strcpy (combined, string);
+  strcat (combined, ": ");
+  strcat (combined, err);
+  fprintf (stderr, "\n%s.\n", combined);
+  fflush (stderr);
+  exit (1);
+}
+
+static void
+sync_error (fp, desc, expect, got)
+     FILE *fp;
+     char *desc;
+     int expect;
+     int got;
+{
+  fprintf (stderr, "\n%s\n", desc);
+  fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
+          ftell (fp), expect, got);
+  fflush (stderr);
+  exit (1);
+}
+
+void
+remote_close()
+{
+  close (remote_desc);
+}
+
+/* Open a connection to a remote debugger.
+   NAME is the filename used for communication.  */
+
+void
+remote_open (name)
+     char *name;
+{
+  struct sgttyb sg;
+  extern char *strchr ();
+
+  if (!strchr (name, ':'))
+    {
+      fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
+      fflush (stderr);
+      exit (1);
+    }
+  else
+    {
+      char *port_str;
+      int port;
+      struct sockaddr_in sockaddr;
+      int tmp;
+      struct protoent *protoent;
+      int tmp_desc;
+
+      port_str = strchr (name, ':');
+
+      port = atoi (port_str + 1);
+
+      tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
+      if (tmp_desc < 0)
+       perror_with_name ("Can't open socket");
+
+      /* Allow rapid reuse of this port. */
+      tmp = 1;
+      setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp,
+                 sizeof(tmp));
+
+      sockaddr.sin_family = PF_INET;
+      sockaddr.sin_port = htons(port);
+      sockaddr.sin_addr.s_addr = INADDR_ANY;
+
+      if (bind (tmp_desc, (struct sockaddr *)&sockaddr, sizeof (sockaddr))
+         || listen (tmp_desc, 1))
+       perror_with_name ("Can't bind address");
+
+      tmp = sizeof (sockaddr);
+      remote_desc = accept (tmp_desc, (struct sockaddr *)&sockaddr, &tmp);
+      if (remote_desc == -1)
+       perror_with_name ("Accept failed");
+
+      protoent = getprotobyname ("tcp");
+      if (!protoent)
+       perror_with_name ("getprotobyname");
+
+      /* Enable TCP keep alive process. */
+      tmp = 1;
+      setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
+
+      /* Tell TCP not to delay small packets.  This greatly speeds up
+        interactive response. */
+      tmp = 1;
+      setsockopt (remote_desc, protoent->p_proto, TCP_NODELAY,
+                 (char *)&tmp, sizeof(tmp));
+
+      close (tmp_desc);                /* No longer need this */
+
+      signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply
+                                   exits when the remote side dies.  */
+    }
+
+  fcntl (remote_desc, F_SETFL, FASYNC);
+
+  fprintf (stderr, "Replay logfile using %s\n", name);
+  fflush (stderr);
+}
+
+static int tohex (ch)
+     int ch;
+{
+  if (ch >= '0' && ch <= '9')
+    {
+      return (ch - '0');
+    }
+  if (ch >= 'A' && ch <= 'F')
+    {
+      return (ch - 'A' + 10);
+    }
+  if (ch >= 'a' && ch <= 'f')
+    {
+      return (ch - 'a' + 10);
+    }
+  fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
+  fflush (stderr);
+  exit (1);
+}
+
+static int
+logchar (fp)
+     FILE *fp;
+{
+  int ch;
+  int ch2;
+
+  ch = fgetc (fp);
+  fputc (ch, stdout);
+  fflush (stdout);
+  switch (ch)
+    {
+    case '\n':
+      ch = EOL;
+      break;
+    case '\\':
+      ch = fgetc (fp);
+      fputc (ch, stdout);
+      fflush (stdout);
+      switch (ch)
+       {
+       case '\\': break;
+       case 'b': ch = '\b'; break;
+       case 'f': ch = '\f'; break;
+       case 'n': ch = '\n'; break;
+       case 'r': ch = '\r'; break;
+       case 't': ch = '\t'; break;
+       case 'v': ch = '\v'; break;
+       case 'x':
+         ch2 = fgetc (fp);
+         fputc (ch2, stdout);
+         fflush (stdout);
+         ch = tohex (ch2) << 4;
+         ch2 = fgetc (fp);
+         fputc (ch2, stdout);
+         fflush (stdout);
+         ch |= tohex (ch2);
+         break;
+       default:
+         /* Treat any other char as just itself */
+         break;
+       }
+    default:
+      break;
+    }
+  return (ch);
+}
+
+/* Accept input from gdb and match with chars from fp (after skipping one
+   blank) up until a \n is read from fp (which is not matched) */
+
+void
+expect (fp)
+     FILE *fp;
+{
+  int fromlog;
+  unsigned char fromgdb;
+
+  if ((fromlog = logchar (fp)) != ' ')
+    {
+      sync_error (fp, "Sync error during gdb read of leading blank", ' ',
+                 fromlog);
+    }
+  do
+    {
+      fromlog = logchar (fp);
+      if (fromlog == EOL)
+       {
+         break;
+       }
+      read (remote_desc, &fromgdb, 1);
+    } while (fromlog == fromgdb);
+  if (fromlog != EOL)
+    {
+      sync_error (fp, "Sync error during read of gdb packet", fromlog,
+                 fromgdb);
+    }
+}
+
+/* Play data back to gdb from fp (after skipping leading blank) up until a
+   \n is read from fp (which is discarded and not sent to gdb). */
+
+void
+play (fp)
+     FILE *fp;
+{
+  int fromlog;
+  char ch;
+
+  if ((fromlog = logchar (fp)) != ' ')
+    {
+      sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
+                 fromlog);
+    }
+  while ((fromlog = logchar (fp)) != EOL)
+    {
+      ch = fromlog;
+      write (remote_desc, &ch, 1);
+    }
+}
+
+int
+main (argc, argv)
+     int argc;
+     char *argv[];
+{
+  FILE *fp;
+  int ch;
+
+  if (argc < 3)
+    {
+      fprintf (stderr, "Usage: gdbreplay <logfile> <host:port>\n");
+      fflush (stderr);
+      exit (1);
+    }
+  fp = fopen (argv[1], "r");
+  if (fp == NULL)
+    {
+      perror_with_name (argv[1]);
+    }      
+  remote_open (argv[2]);
+  while ((ch = logchar (fp)) != EOF)
+    {
+      switch (ch)
+       {
+       case 'w':
+         /* data sent from gdb to gdbreplay, accept and match it */
+         expect (fp);
+         break;
+       case 'r':
+         /* data sent from gdbreplay to gdb, play it */
+         play (fp);
+         break;
+       case 'c':
+         /* Command executed by gdb */
+         while ((ch = logchar (fp)) != EOL);
+         break;
+       }
+    }
+  remote_close ();
+  exit (0);
+}
+
index 046a9be369fd356c793af5d2fbbf26b34a1bdf4c..34dc64355f69216b7b4eb3a060c022a9d2d0afc8 100644 (file)
@@ -273,7 +273,6 @@ store_inferior_registers (regno)
 {
   register unsigned int regaddr;
   char buf[80];
-  extern char registers[];
   register int i;
   unsigned int offset = U_REGS_OFFSET;
   int scratch;
index 0b36af1880fef11faf116d8732aed63a73f9d6e2..0ed84cade2c37db40d82752fe9ff56c48d20a4c9 100644 (file)
 
 extern int baud_rate;
 
-static const char hexchars[]="0123456789abcdef";
-static char *hex2mem();
-
-#define SREC_SIZE 160
 #define ARRAY_PROMPT ">> "
 
 #define SWAP_TARGET_AND_HOST(buffer,len)                               \
@@ -758,8 +754,10 @@ array_wait (pid, status)
       /* do this so it looks like there's keyboard echo */
       if (c == 3)              /* exit on Control-C */
        break;
+#if 0
       fputc_unfiltered (c, gdb_stdout);
       fflush (stdout);
+#endif
     }
   }
   SERIAL_SET_TTY_STATE (tty_desc, ttystate);
@@ -947,21 +945,12 @@ array_read_inferior_memory(memaddr, myaddr, len)
      char *myaddr;
      int len;
 {
-  int i, j;
+  int j;
   char buf[20];
   char packet[PBUFSIZ];
-
-  /* Number of bytes read so far.  */
-  int count;
-
-  /* Starting address of this pass.  */
-  unsigned long startaddr;
-
-  /* Starting address of this pass.  */
-  unsigned long endaddr;
-
-  /* Number of bytes to read in this pass.  */
-  int len_this_pass;
+  int count;                   /* Number of bytes read so far.  */
+  unsigned long startaddr;     /* Starting address of this pass.  */
+  int len_this_pass;           /* Number of bytes to read in this pass.  */
 
   debuglogs (1, "array_read_inferior_memory (memaddr=0x%x, myaddr=0x%x, len=%d)", memaddr, myaddr, len);
 
@@ -979,36 +968,46 @@ array_read_inferior_memory(memaddr, myaddr, len)
     return 0;
   }
   
-  startaddr = memaddr;
-  count = 0;
-  while (count < len) {
-    len_this_pass = 16;
-    if ((startaddr % 16) != 0)
-      len_this_pass -= startaddr % 16;
-    if (len_this_pass > (len - count))
-      len_this_pass = (len - count);
-    
-    debuglogs (3, "Display %d bytes at %x for Big Endian host", len_this_pass, startaddr);
-    
-    for (i = 0; i < len_this_pass; i++) {
+  for (count = 0, startaddr = memaddr; count < len; startaddr += len_this_pass)
+    {
+      /* Try to align to 16 byte boundry (why?) */
+      len_this_pass = 16;
+      if ((startaddr % 16) != 0)
+       {
+         len_this_pass -= startaddr % 16;
+       }
+      /* Only transfer bytes we need */
+      if (len_this_pass > (len - count))
+       {
+         len_this_pass = (len - count);
+       }
+      /* Fetch the bytes */
+      debuglogs (3, "read %d bytes from inferior address %x", len_this_pass,
+                startaddr);
       sprintf (buf, "m%08x,%04x", startaddr, len_this_pass);
       make_gdb_packet (packet, buf);
       if (array_send_packet (packet) == 0)
-       error ("Couldn't transmit packet\n");
+       {
+         error ("Couldn't transmit packet\n");
+       }
       if (array_get_packet (packet) == 0)
-       error ("Couldn't receive packet\n");  
+       {
+         error ("Couldn't receive packet\n");  
+       }
       if (*packet == 0)
-       error ("Got no data in the GDB packet\n");
-      debuglogs (4, "array_read_inferior: Got a \"%s\" back\n", packet);
-      for (j = 0; j < len_this_pass ; j++) {           /* extract the byte values */
-       myaddr[count++] = from_hex (*(packet+(j*2))) * 16 + from_hex (*(packet+(j*2)+1));
-       debuglogs (5, "myaddr set to %x\n", myaddr[count-1]);
-      }
-      startaddr += 1;
+       {
+         error ("Got no data in the GDB packet\n");
+       }
+      /* Pick packet apart and xfer bytes to myaddr */
+      debuglogs (4, "array_read_inferior_memory: Got a \"%s\" back\n", packet);
+      for (j = 0; j < len_this_pass ; j++)
+       {
+         /* extract the byte values */
+         myaddr[count++] = from_hex (*(packet+(j*2))) * 16 + from_hex (*(packet+(j*2)+1));
+         debuglogs (5, "myaddr[%d] set to %x\n", count-1, myaddr[count-1]);
+       }
     }
-
-  }
-  return len;
+  return (count);
 }
 
 /* FIXME-someday!  merge these two.  */
index 72bfc5077137640c0853ae4fbde17bf0b4506e36..c984d7ae56feee8ca0a1ef7cc538456c2924600e 100644 (file)
@@ -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;
+
+\f
+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 <CR>~. or <CR>~^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);
+
 }
index 2cf06f36f5b84f56c8e6d7fbccad77233c665bbf..8abcb3d077b3369a4d4493c484c663125b1f1fec 100644 (file)
@@ -136,7 +136,9 @@ serial_t serial_fdopen PARAMS ((const int fd));
 #define SERIAL_TIMEOUT -2
 #define SERIAL_EOF -3
 
-#define SERIAL_READCHAR(SERIAL_T, TIMEOUT) ((SERIAL_T)->ops->readchar((SERIAL_T), TIMEOUT))
+extern int serial_readchar PARAMS ((serial_t scb, int timeout));
+
+#define SERIAL_READCHAR(SERIAL_T, TIMEOUT)  serial_readchar (SERIAL_T, TIMEOUT)
 
 /* Set the baudrate to the decimal value supplied.  Returns 0 for success,
    -1 for failure.  */
@@ -155,11 +157,13 @@ serial_t serial_fdopen PARAMS ((const int fd));
 /* Write LEN chars from STRING to the port SERIAL_T.  Returns 0 for
    success, non-zero for failure.  */
 
-#define SERIAL_WRITE(SERIAL_T, STRING, LEN) ((SERIAL_T)->ops->write((SERIAL_T), STRING, LEN))
+extern int serial_write PARAMS ((serial_t scb, const char *str, int len));
+
+#define SERIAL_WRITE(SERIAL_T, STRING,LEN)  serial_write (SERIAL_T, STRING, LEN)
 
 /* Push out all buffers, close the device and destroy SERIAL_T. */
 
-void serial_close PARAMS ((serial_t, int));
+extern void serial_close PARAMS ((serial_t, int));
 
 #define SERIAL_CLOSE(SERIAL_T) serial_close(SERIAL_T, 1)
 
@@ -170,4 +174,9 @@ void serial_close PARAMS ((serial_t, int));
 extern void serial_printf PARAMS ((serial_t desc, const char *, ...))
      ATTR_FORMAT(printf, 2, 3);
 
+/* File in which to record the remote debugging session */
+
+extern char *serial_logfile;
+extern FILE *serial_logfp;
+
 #endif /* SERIAL_H */
index 675ad802b4af8a13cb86b97621a87c6fab666f94..cf22bce58e0d892cfb1488bbf902659f7d463006 100644 (file)
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1139,6 +1139,7 @@ execute_command (p, from_tty)
   register struct cmd_list_element *c;
   register enum language flang;
   static int warned = 0;
+  extern FILE *serial_logfp;
 
   free_all_values ();
 
@@ -1146,6 +1147,9 @@ execute_command (p, from_tty)
   if (p == NULL)
       return;
 
+  if (serial_logfp != NULL)
+    serial_log_command (p);
+
   while (*p == ' ' || *p == '\t') p++;
   if (*p)
     {