* 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.
This commit is contained in:
parent
76e45938c3
commit
e8f1ad9a8b
8 changed files with 551 additions and 45 deletions
|
@ -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>
|
Tue Jan 23 18:02:35 1996 Per Bothner <bothner@kalessin.cygnus.com>
|
||||||
|
|
||||||
* stabsread.c (rs6000_builtin_type): Make bool type unsigned.
|
* stabsread.c (rs6000_builtin_type): Make bool type unsigned.
|
||||||
|
|
10
gdb/NEWS
10
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
|
/usr/lib/end.o into your program. This feature should work automatically
|
||||||
on hpux10.
|
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:
|
*** Changes in GDB-4.15:
|
||||||
|
|
||||||
* Psymtabs for XCOFF
|
* Psymtabs for XCOFF
|
||||||
|
|
319
gdb/gdbserver/gdbreplay.c
Normal file
319
gdb/gdbserver/gdbreplay.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -273,7 +273,6 @@ store_inferior_registers (regno)
|
||||||
{
|
{
|
||||||
register unsigned int regaddr;
|
register unsigned int regaddr;
|
||||||
char buf[80];
|
char buf[80];
|
||||||
extern char registers[];
|
|
||||||
register int i;
|
register int i;
|
||||||
unsigned int offset = U_REGS_OFFSET;
|
unsigned int offset = U_REGS_OFFSET;
|
||||||
int scratch;
|
int scratch;
|
||||||
|
|
|
@ -43,10 +43,6 @@
|
||||||
|
|
||||||
extern int baud_rate;
|
extern int baud_rate;
|
||||||
|
|
||||||
static const char hexchars[]="0123456789abcdef";
|
|
||||||
static char *hex2mem();
|
|
||||||
|
|
||||||
#define SREC_SIZE 160
|
|
||||||
#define ARRAY_PROMPT ">> "
|
#define ARRAY_PROMPT ">> "
|
||||||
|
|
||||||
#define SWAP_TARGET_AND_HOST(buffer,len) \
|
#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 */
|
/* do this so it looks like there's keyboard echo */
|
||||||
if (c == 3) /* exit on Control-C */
|
if (c == 3) /* exit on Control-C */
|
||||||
break;
|
break;
|
||||||
|
#if 0
|
||||||
fputc_unfiltered (c, gdb_stdout);
|
fputc_unfiltered (c, gdb_stdout);
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SERIAL_SET_TTY_STATE (tty_desc, ttystate);
|
SERIAL_SET_TTY_STATE (tty_desc, ttystate);
|
||||||
|
@ -947,21 +945,12 @@ array_read_inferior_memory(memaddr, myaddr, len)
|
||||||
char *myaddr;
|
char *myaddr;
|
||||||
int len;
|
int len;
|
||||||
{
|
{
|
||||||
int i, j;
|
int j;
|
||||||
char buf[20];
|
char buf[20];
|
||||||
char packet[PBUFSIZ];
|
char packet[PBUFSIZ];
|
||||||
|
int count; /* Number of bytes read so far. */
|
||||||
/* Number of bytes read so far. */
|
unsigned long startaddr; /* Starting address of this pass. */
|
||||||
int count;
|
int len_this_pass; /* Number of bytes to read in this pass. */
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
debuglogs (1, "array_read_inferior_memory (memaddr=0x%x, myaddr=0x%x, len=%d)", memaddr, myaddr, len);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
startaddr = memaddr;
|
for (count = 0, startaddr = memaddr; count < len; startaddr += len_this_pass)
|
||||||
count = 0;
|
{
|
||||||
while (count < len) {
|
/* Try to align to 16 byte boundry (why?) */
|
||||||
len_this_pass = 16;
|
len_this_pass = 16;
|
||||||
if ((startaddr % 16) != 0)
|
if ((startaddr % 16) != 0)
|
||||||
len_this_pass -= startaddr % 16;
|
{
|
||||||
if (len_this_pass > (len - count))
|
len_this_pass -= startaddr % 16;
|
||||||
len_this_pass = (len - count);
|
}
|
||||||
|
/* Only transfer bytes we need */
|
||||||
debuglogs (3, "Display %d bytes at %x for Big Endian host", len_this_pass, startaddr);
|
if (len_this_pass > (len - count))
|
||||||
|
{
|
||||||
for (i = 0; i < len_this_pass; i++) {
|
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);
|
sprintf (buf, "m%08x,%04x", startaddr, len_this_pass);
|
||||||
make_gdb_packet (packet, buf);
|
make_gdb_packet (packet, buf);
|
||||||
if (array_send_packet (packet) == 0)
|
if (array_send_packet (packet) == 0)
|
||||||
error ("Couldn't transmit packet\n");
|
{
|
||||||
|
error ("Couldn't transmit packet\n");
|
||||||
|
}
|
||||||
if (array_get_packet (packet) == 0)
|
if (array_get_packet (packet) == 0)
|
||||||
error ("Couldn't receive packet\n");
|
{
|
||||||
|
error ("Couldn't receive packet\n");
|
||||||
|
}
|
||||||
if (*packet == 0)
|
if (*packet == 0)
|
||||||
error ("Got no data in the GDB packet\n");
|
{
|
||||||
debuglogs (4, "array_read_inferior: Got a \"%s\" back\n", packet);
|
error ("Got no data in the GDB packet\n");
|
||||||
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));
|
/* Pick packet apart and xfer bytes to myaddr */
|
||||||
debuglogs (5, "myaddr set to %x\n", myaddr[count-1]);
|
debuglogs (4, "array_read_inferior_memory: Got a \"%s\" back\n", packet);
|
||||||
}
|
for (j = 0; j < len_this_pass ; j++)
|
||||||
startaddr += 1;
|
{
|
||||||
|
/* 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 (count);
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME-someday! merge these two. */
|
/* FIXME-someday! merge these two. */
|
||||||
|
|
134
gdb/serial.c
134
gdb/serial.c
|
@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "gdb_string.h"
|
#include "gdb_string.h"
|
||||||
|
#include "gdbcmd.h"
|
||||||
|
|
||||||
/* Linked list of serial I/O handlers */
|
/* Linked list of serial I/O handlers */
|
||||||
|
|
||||||
|
@ -33,6 +34,110 @@ static serial_t last_serial_opened = NULL;
|
||||||
|
|
||||||
static serial_t scb_base;
|
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 *
|
static struct serial_ops *
|
||||||
serial_interface_lookup (name)
|
serial_interface_lookup (name)
|
||||||
char *name;
|
char *name;
|
||||||
|
@ -102,6 +207,15 @@ serial_open (name)
|
||||||
|
|
||||||
last_serial_opened = scb;
|
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;
|
return scb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +266,18 @@ serial_close(scb, really_close)
|
||||||
|
|
||||||
last_serial_opened = NULL;
|
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
|
/* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you
|
||||||
should fix your code instead. */
|
should fix your code instead. */
|
||||||
|
|
||||||
|
@ -346,4 +472,12 @@ _initialize_serial ()
|
||||||
"Connect the terminal directly up to the command monitor.\n\
|
"Connect the terminal directly up to the command monitor.\n\
|
||||||
Use <CR>~. or <CR>~^D to break out.");
|
Use <CR>~. or <CR>~^D to break out.");
|
||||||
#endif /* 0 */
|
#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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
15
gdb/serial.h
15
gdb/serial.h
|
@ -136,7 +136,9 @@ serial_t serial_fdopen PARAMS ((const int fd));
|
||||||
#define SERIAL_TIMEOUT -2
|
#define SERIAL_TIMEOUT -2
|
||||||
#define SERIAL_EOF -3
|
#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,
|
/* Set the baudrate to the decimal value supplied. Returns 0 for success,
|
||||||
-1 for failure. */
|
-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
|
/* Write LEN chars from STRING to the port SERIAL_T. Returns 0 for
|
||||||
success, non-zero for failure. */
|
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. */
|
/* 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)
|
#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 *, ...))
|
extern void serial_printf PARAMS ((serial_t desc, const char *, ...))
|
||||||
ATTR_FORMAT(printf, 2, 3);
|
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 */
|
#endif /* SERIAL_H */
|
||||||
|
|
|
@ -1139,6 +1139,7 @@ execute_command (p, from_tty)
|
||||||
register struct cmd_list_element *c;
|
register struct cmd_list_element *c;
|
||||||
register enum language flang;
|
register enum language flang;
|
||||||
static int warned = 0;
|
static int warned = 0;
|
||||||
|
extern FILE *serial_logfp;
|
||||||
|
|
||||||
free_all_values ();
|
free_all_values ();
|
||||||
|
|
||||||
|
@ -1146,6 +1147,9 @@ execute_command (p, from_tty)
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (serial_logfp != NULL)
|
||||||
|
serial_log_command (p);
|
||||||
|
|
||||||
while (*p == ' ' || *p == '\t') p++;
|
while (*p == ' ' || *p == '\t') p++;
|
||||||
if (*p)
|
if (*p)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue