gdbreplay: Add --debug-logging option

As gdbreplay communicates with GDB, it outputs all the remote
protocol communication it reads from the remotelogfile to stderr.
This patch disables this behavior by default but adds the new
--debug-logging option which turns printing the packets
to stderr on again.

The motivation for this change is to make it possible to use
gdbreplay with TCL tests. Printing the whole remotelog file out
seems to overflow the expect cache wich causes gdbreplay to not
to get the packet its expects and results in going out of sync
with GDB. Other motivation is making communication between GDB
and gdbreplay faster as printing bigger remotelogfile takes
considerable amount of time.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
This commit is contained in:
Alexandra Hájková 2024-10-16 13:25:41 +02:00
parent 32ffcd0737
commit 0cb7f3a837
2 changed files with 61 additions and 23 deletions

View File

@ -125,8 +125,9 @@ Then start GDB (preferably in a different screen or window) and use the
Repeat the same sequence of user commands to GDB that you gave in the Repeat the same sequence of user commands to GDB that you gave in the
original debug session. GDB should not be able to tell that it is talking original debug session. GDB should not be able to tell that it is talking
to GDBreplay rather than a real target, all other things being equal. Note to GDBreplay rather than a real target, all other things being equal.
that GDBreplay echos the command lines to stderr, as well as the contents of
the packets it sends and receives. The last command echoed by GDBreplay is As GDBreplay communicates with GDB, it outputs only the commands
the next command that needs to be typed to GDB to continue the session in it expects from GDB. The --debug-logging option turns printing the
sync with the original session. remotelogfile to stderr on. GDBreplay then echos the command lines
to stderr, as well as the contents of the packets it sends and receives.

View File

@ -68,6 +68,9 @@ typedef int socklen_t;
static int remote_desc_in; static int remote_desc_in;
static int remote_desc_out; static int remote_desc_out;
/* When true all packets are printed to stderr as they are handled by
gdbreplay. */
bool debug_logging = false;
static void static void
sync_error (FILE *fp, const char *desc, int expect, int got) sync_error (FILE *fp, const char *desc, int expect, int got)
@ -261,13 +264,13 @@ remote_open (const char *name)
} }
static int static int
logchar (FILE *fp) logchar (FILE *fp, bool print)
{ {
int ch; int ch;
int ch2; int ch2;
ch = fgetc (fp); ch = fgetc (fp);
if (ch != '\r') if (ch != '\r' && (print || debug_logging))
{ {
fputc (ch, stderr); fputc (ch, stderr);
fflush (stderr); fflush (stderr);
@ -284,16 +287,22 @@ logchar (FILE *fp)
ungetc (ch, fp); ungetc (ch, fp);
ch = '\r'; ch = '\r';
} }
fputc (ch == EOL ? '\n' : '\r', stderr); if (print || debug_logging)
fflush (stderr); {
fputc (ch == EOL ? '\n' : '\r', stderr);
fflush (stderr);
}
break; break;
case '\n': case '\n':
ch = EOL; ch = EOL;
break; break;
case '\\': case '\\':
ch = fgetc (fp); ch = fgetc (fp);
fputc (ch, stderr); if (print || debug_logging)
fflush (stderr); {
fputc (ch, stderr);
fflush (stderr);
}
switch (ch) switch (ch)
{ {
case '\\': case '\\':
@ -318,14 +327,28 @@ logchar (FILE *fp)
break; break;
case 'x': case 'x':
ch2 = fgetc (fp); ch2 = fgetc (fp);
fputc (ch2, stderr); if (print || debug_logging)
fflush (stderr); {
fputc (ch2, stderr);
fflush (stderr);
}
ch = fromhex (ch2) << 4; ch = fromhex (ch2) << 4;
ch2 = fgetc (fp); ch2 = fgetc (fp);
fputc (ch2, stderr); if (print || debug_logging)
fflush (stderr); {
fputc (ch2, stderr);
fflush (stderr);
}
ch |= fromhex (ch2); ch |= fromhex (ch2);
break; break;
case 'c':
fputc (ch, stderr);
fflush (stderr);
break;
case 'E':
fputc (ch, stderr);
fflush (stderr);
break;
default: default:
/* Treat any other char as just itself */ /* Treat any other char as just itself */
break; break;
@ -356,14 +379,14 @@ expect (FILE *fp)
int fromlog; int fromlog;
int fromgdb; int fromgdb;
if ((fromlog = logchar (fp)) != ' ') if ((fromlog = logchar (fp, false)) != ' ')
{ {
sync_error (fp, "Sync error during gdb read of leading blank", ' ', sync_error (fp, "Sync error during gdb read of leading blank", ' ',
fromlog); fromlog);
} }
do do
{ {
fromlog = logchar (fp); fromlog = logchar (fp, false);
if (fromlog == EOL) if (fromlog == EOL)
break; break;
fromgdb = gdbchar (remote_desc_in); fromgdb = gdbchar (remote_desc_in);
@ -388,12 +411,12 @@ play (FILE *fp)
int fromlog; int fromlog;
char ch; char ch;
if ((fromlog = logchar (fp)) != ' ') if ((fromlog = logchar (fp, false)) != ' ')
{ {
sync_error (fp, "Sync error skipping blank during write to gdb", ' ', sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
fromlog); fromlog);
} }
while ((fromlog = logchar (fp)) != EOL) while ((fromlog = logchar (fp, false)) != EOL)
{ {
ch = fromlog; ch = fromlog;
if (write (remote_desc_out, &ch, 1) != 1) if (write (remote_desc_out, &ch, 1) != 1)
@ -428,11 +451,12 @@ captured_main (int argc, char *argv[])
{ {
FILE *fp; FILE *fp;
int ch, optc; int ch, optc;
enum opts { OPT_VERSION = 1, OPT_HELP }; enum opts { OPT_VERSION = 1, OPT_HELP, OPT_LOGGING };
static struct option longopts[] = static struct option longopts[] =
{ {
{"version", no_argument, nullptr, OPT_VERSION}, {"version", no_argument, nullptr, OPT_VERSION},
{"help", no_argument, nullptr, OPT_HELP}, {"help", no_argument, nullptr, OPT_HELP},
{"debug-logging", no_argument, nullptr, OPT_LOGGING},
{nullptr, no_argument, nullptr, 0} {nullptr, no_argument, nullptr, 0}
}; };
@ -446,6 +470,9 @@ captured_main (int argc, char *argv[])
case OPT_HELP: case OPT_HELP:
gdbreplay_usage (stdout); gdbreplay_usage (stdout);
exit (0); exit (0);
case OPT_LOGGING:
debug_logging = true;
break;
} }
} }
@ -460,7 +487,7 @@ captured_main (int argc, char *argv[])
perror_with_name (argv[optind]); perror_with_name (argv[optind]);
} }
remote_open (argv[optind + 1]); remote_open (argv[optind + 1]);
while ((ch = logchar (fp)) != EOF) while ((ch = logchar (fp, false)) != EOF)
{ {
switch (ch) switch (ch)
{ {
@ -473,8 +500,18 @@ captured_main (int argc, char *argv[])
play (fp); play (fp);
break; break;
case 'c': case 'c':
/* Command executed by gdb */ /* We want to always print the command executed by GDB. */
while ((ch = logchar (fp)) != EOL); if (!debug_logging)
{
fprintf (stderr, "\n");
fprintf (stderr, "Command expected from GDB:\n");
}
while ((ch = logchar (fp, true)) != EOL);
break;
case 'E':
if (!debug_logging)
fprintf (stderr, "E");
while ((ch = logchar (fp, true)) != EOL);
break; break;
} }
} }