Automatic date update in version.in
[binutils-gdb.git] / gdbserver / gdbreplay.cc
blob58e584b06535c9683aaaad145288883161908a10
1 /* Replay a remote debug session logfile for GDB.
2 Copyright (C) 1996-2024 Free Software Foundation, Inc.
3 Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #undef PACKAGE
21 #undef PACKAGE_NAME
22 #undef PACKAGE_VERSION
23 #undef PACKAGE_STRING
24 #undef PACKAGE_TARNAME
26 #include <config.h>
27 #include "gdbsupport/version.h"
29 #if HAVE_SYS_FILE_H
30 #include <sys/file.h>
31 #endif
32 #if HAVE_SIGNAL_H
33 #include <signal.h>
34 #endif
35 #include <ctype.h>
36 #if HAVE_FCNTL_H
37 #include <fcntl.h>
38 #endif
39 #include <unistd.h>
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
42 #endif
43 #ifdef HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
45 #endif
46 #if HAVE_NETDB_H
47 #include <netdb.h>
48 #endif
49 #if HAVE_NETINET_TCP_H
50 #include <netinet/tcp.h>
51 #endif
53 #if USE_WIN32API
54 #include <ws2tcpip.h>
55 #endif
57 #include "gdbsupport/netstuff.h"
58 #include "gdbsupport/rsp-low.h"
60 #include "getopt.h"
62 #ifndef HAVE_SOCKLEN_T
63 typedef int socklen_t;
64 #endif
66 /* Sort of a hack... */
67 #define EOL (EOF - 1)
69 static int remote_desc_in;
70 static int remote_desc_out;
71 /* When true all packets are printed to stderr as they are handled by
72 gdbreplay. */
73 bool debug_logging = false;
75 static void
76 sync_error (FILE *fp, const char *desc, int expect, int got)
78 fprintf (stderr, "\n%s\n", desc);
79 fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
80 ftell (fp), expect, got);
81 fflush (stderr);
82 exit (1);
85 static void
86 remote_error (const char *desc)
88 fprintf (stderr, "\n%s\n", desc);
89 fflush (stderr);
90 exit (1);
93 static void
94 remote_close (void)
96 #ifdef USE_WIN32API
97 gdb_assert (remote_desc_in == remote_desc_out);
98 closesocket (remote_desc_in);
99 #else
100 close (remote_desc_in);
101 if (remote_desc_in != remote_desc_out)
102 close (remote_desc_out);
103 #endif
106 /* Open a connection to a remote debugger.
107 NAME is the filename used for communication. */
109 static void
110 remote_open (const char *name)
112 #ifndef USE_WIN32API
113 if (strcmp (name, "-") == 0)
115 remote_desc_in = 0;
116 remote_desc_out = 1;
117 return;
119 #endif
121 const char *last_colon = strrchr (name, ':');
123 if (last_colon == NULL)
125 fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
126 fflush (stderr);
127 exit (1);
130 #ifdef USE_WIN32API
131 static int winsock_initialized;
132 #endif
133 int tmp;
134 int tmp_desc;
135 struct addrinfo hint;
136 struct addrinfo *ainfo;
138 memset (&hint, 0, sizeof (hint));
139 /* Assume no prefix will be passed, therefore we should use
140 AF_UNSPEC. */
141 hint.ai_family = AF_UNSPEC;
142 hint.ai_socktype = SOCK_STREAM;
143 hint.ai_protocol = IPPROTO_TCP;
145 parsed_connection_spec parsed = parse_connection_spec (name, &hint);
147 if (parsed.port_str.empty ())
148 error (_("Missing port on hostname '%s'"), name);
150 #ifdef USE_WIN32API
151 if (!winsock_initialized)
153 WSADATA wsad;
155 WSAStartup (MAKEWORD (1, 0), &wsad);
156 winsock_initialized = 1;
158 #endif
160 int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (),
161 &hint, &ainfo);
163 if (r != 0)
165 fprintf (stderr, "%s:%s: cannot resolve name: %s\n",
166 parsed.host_str.c_str (), parsed.port_str.c_str (),
167 gai_strerror (r));
168 fflush (stderr);
169 exit (1);
172 scoped_free_addrinfo free_ainfo (ainfo);
174 struct addrinfo *p;
176 for (p = ainfo; p != NULL; p = p->ai_next)
178 tmp_desc = socket (p->ai_family, p->ai_socktype, p->ai_protocol);
180 if (tmp_desc >= 0)
181 break;
184 if (p == NULL)
185 perror_with_name ("Cannot open socket");
187 /* Allow rapid reuse of this port. */
188 tmp = 1;
189 setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
190 sizeof (tmp));
192 switch (p->ai_family)
194 case AF_INET:
195 ((struct sockaddr_in *) p->ai_addr)->sin_addr.s_addr = INADDR_ANY;
196 break;
197 case AF_INET6:
198 ((struct sockaddr_in6 *) p->ai_addr)->sin6_addr = in6addr_any;
199 break;
200 default:
201 fprintf (stderr, "Invalid 'ai_family' %d\n", p->ai_family);
202 exit (1);
205 if (bind (tmp_desc, p->ai_addr, p->ai_addrlen) != 0)
206 perror_with_name ("Can't bind address");
208 fprintf (stderr, "Replay logfile using %s\n", name);
209 fflush (stderr);
210 if (p->ai_socktype == SOCK_DGRAM)
211 remote_desc_in = tmp_desc;
212 else
214 struct sockaddr_storage sockaddr;
215 socklen_t sockaddrsize = sizeof (sockaddr);
216 char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT];
218 if (listen (tmp_desc, 1) != 0)
219 perror_with_name ("Can't listen on socket");
221 remote_desc_in = accept (tmp_desc, (struct sockaddr *) &sockaddr,
222 &sockaddrsize);
224 if (remote_desc_in == -1)
225 perror_with_name ("Accept failed");
227 /* Enable TCP keep alive process. */
228 tmp = 1;
229 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE,
230 (char *) &tmp, sizeof (tmp));
232 /* Tell TCP not to delay small packets. This greatly speeds up
233 interactive response. */
234 tmp = 1;
235 setsockopt (remote_desc_in, IPPROTO_TCP, TCP_NODELAY,
236 (char *) &tmp, sizeof (tmp));
238 if (getnameinfo ((struct sockaddr *) &sockaddr, sockaddrsize,
239 orig_host, sizeof (orig_host),
240 orig_port, sizeof (orig_port),
241 NI_NUMERICHOST | NI_NUMERICSERV) == 0)
243 fprintf (stderr, "Remote debugging from host %s, port %s\n",
244 orig_host, orig_port);
245 fflush (stderr);
248 #ifndef USE_WIN32API
249 close (tmp_desc); /* No longer need this */
251 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then
252 gdbreplay simply exits when
253 the remote side dies. */
254 #else
255 closesocket (tmp_desc); /* No longer need this */
256 #endif
259 #if defined(F_SETFL) && defined (FASYNC)
260 fcntl (remote_desc_in, F_SETFL, FASYNC);
261 #endif
262 remote_desc_out = remote_desc_in;
265 static int
266 logchar (FILE *fp, bool print)
268 int ch;
269 int ch2;
271 ch = fgetc (fp);
272 if (ch != '\r' && (print || debug_logging))
274 fputc (ch, stderr);
275 fflush (stderr);
277 switch (ch)
279 /* Treat \r\n as a newline. */
280 case '\r':
281 ch = fgetc (fp);
282 if (ch == '\n')
283 ch = EOL;
284 else
286 ungetc (ch, fp);
287 ch = '\r';
289 if (print || debug_logging)
291 fputc (ch == EOL ? '\n' : '\r', stderr);
292 fflush (stderr);
294 break;
295 case '\n':
296 ch = EOL;
297 break;
298 case '\\':
299 ch = fgetc (fp);
300 if (print || debug_logging)
302 fputc (ch, stderr);
303 fflush (stderr);
305 switch (ch)
307 case '\\':
308 break;
309 case 'b':
310 ch = '\b';
311 break;
312 case 'f':
313 ch = '\f';
314 break;
315 case 'n':
316 ch = '\n';
317 break;
318 case 'r':
319 ch = '\r';
320 break;
321 case 't':
322 ch = '\t';
323 break;
324 case 'v':
325 ch = '\v';
326 break;
327 case 'x':
328 ch2 = fgetc (fp);
329 if (print || debug_logging)
331 fputc (ch2, stderr);
332 fflush (stderr);
334 ch = fromhex (ch2) << 4;
335 ch2 = fgetc (fp);
336 if (print || debug_logging)
338 fputc (ch2, stderr);
339 fflush (stderr);
341 ch |= fromhex (ch2);
342 break;
343 case 'c':
344 fputc (ch, stderr);
345 fflush (stderr);
346 break;
347 case 'E':
348 fputc (ch, stderr);
349 fflush (stderr);
350 break;
351 default:
352 /* Treat any other char as just itself */
353 break;
355 default:
356 break;
358 return (ch);
361 static int
362 gdbchar (int desc)
364 unsigned char fromgdb;
366 if (read (desc, &fromgdb, 1) != 1)
367 return -1;
368 else
369 return fromgdb;
372 /* Accept input from gdb and match with chars from fp (after skipping one
373 blank) up until a \n is read from fp (which is not matched) */
375 static void
376 expect (FILE *fp)
378 int fromlog;
379 int fromgdb;
381 if ((fromlog = logchar (fp, false)) != ' ')
383 sync_error (fp, "Sync error during gdb read of leading blank", ' ',
384 fromlog);
388 fromlog = logchar (fp, false);
389 if (fromlog == EOL)
390 break;
391 fromgdb = gdbchar (remote_desc_in);
392 if (fromgdb < 0)
393 remote_error ("Error during read from gdb");
395 while (fromlog == fromgdb);
397 if (fromlog != EOL)
399 sync_error (fp, "Sync error during read of gdb packet from log", fromlog,
400 fromgdb);
404 /* Calculate checksum for the packet stored in buffer buf. Store
405 the checksum in a hexadecimal format in a checksum_hex variable. */
406 static void
407 recalculate_csum (const std::string &buf, int off, unsigned char *checksum_hex)
409 unsigned char csum = 0;
411 int len = buf.length ();
412 for (int i = off; i < len; ++i)
413 csum += buf[i];
415 checksum_hex[0] = tohex ((csum >> 4) & 0xf);
416 checksum_hex[1] = tohex (csum & 0xf);
419 /* Play data back to gdb from fp (after skipping leading blank) up until a
420 \n is read from fp (which is discarded and not sent to gdb). */
422 static void
423 play (FILE *fp)
425 int fromlog;
426 int where_csum = 0, offset = 1;
427 unsigned char checksum[2] = {0, 0};
428 std::string line;
431 if ((fromlog = logchar (fp, false)) != ' ')
433 sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
434 fromlog);
436 while ((fromlog = logchar (fp, false)) != EOL)
438 if (fromlog == '#')
439 where_csum = line.length ();
440 line.push_back (fromlog);
443 /* Packet starts with '+$' or '$', we don't want to calculate those
444 to the checksum, substract the offset to adjust the line length.
445 If the line starts with '$', the offset remains set to 1. */
446 if (line[0] == '+')
447 offset = 2;
449 if (where_csum > 0)
450 line.resize (where_csum);
451 recalculate_csum (line, offset, checksum);
453 line.push_back ('#');
454 line.push_back (checksum[0]);
455 line.push_back (checksum[1]);
457 if (write (remote_desc_out, line.data (), line.size ()) != line.size ())
458 remote_error ("Error during write to gdb");
461 static void
462 gdbreplay_version (void)
464 printf ("GNU gdbreplay %s%s\n"
465 "Copyright (C) 2024 Free Software Foundation, Inc.\n"
466 "gdbreplay is free software, covered by "
467 "the GNU General Public License.\n"
468 "This gdbreplay was configured as \"%s\"\n",
469 PKGVERSION, version, host_name);
472 static void
473 gdbreplay_usage (FILE *stream)
475 fprintf (stream, "Usage:\tgdbreplay LOGFILE HOST:PORT\n");
478 static void
479 gdbreplay_help ()
481 gdbreplay_usage (stdout);
483 printf ("\n");
484 printf ("LOGFILE is a file generated by 'set remotelogfile' in gdb.\n");
485 printf ("COMM may either be a tty device (for serial debugging),\n");
486 printf ("HOST:PORT to listen for a TCP connection, or '-' or 'stdio' to use\n");
487 printf ("stdin/stdout of gdbserver.\n");
488 printf ("\n");
490 printf ("Options:\n\n");
491 printf (" --debug-logging Show packets as they are processed.\n");
492 printf (" --help Print this message and then exit.\n");
493 printf (" --version Display version information and then exit.\n");
494 if (REPORT_BUGS_TO[0])
496 printf ("\n");
497 printf ("Report bugs to \"%s\".\n", REPORT_BUGS_TO);
501 /* Main function. This is called by the real "main" function,
502 wrapped in a TRY_CATCH that handles any uncaught exceptions. */
504 [[noreturn]] static void
505 captured_main (int argc, char *argv[])
507 FILE *fp;
508 int ch, optc;
509 enum opts { OPT_VERSION = 1, OPT_HELP, OPT_LOGGING };
510 static struct option longopts[] =
512 {"version", no_argument, nullptr, OPT_VERSION},
513 {"help", no_argument, nullptr, OPT_HELP},
514 {"debug-logging", no_argument, nullptr, OPT_LOGGING},
515 {nullptr, no_argument, nullptr, 0}
518 while ((optc = getopt_long (argc, argv, "", longopts, nullptr)) != -1)
520 switch (optc)
522 case OPT_VERSION:
523 gdbreplay_version ();
524 exit (0);
525 case OPT_HELP:
526 gdbreplay_help ();
527 exit (0);
528 case OPT_LOGGING:
529 debug_logging = true;
530 break;
532 case '?':
533 fprintf (stderr,
534 "Use 'gdbreplay --help' for a complete list of options.\n");
535 exit (1);
539 if (optind + 2 != argc)
541 gdbreplay_usage (stderr);
542 exit (1);
544 fp = fopen (argv[optind], "r");
545 if (fp == NULL)
547 perror_with_name (argv[optind]);
549 remote_open (argv[optind + 1]);
550 while ((ch = logchar (fp, false)) != EOF)
552 switch (ch)
554 case 'w':
555 /* data sent from gdb to gdbreplay, accept and match it */
556 expect (fp);
557 break;
558 case 'r':
559 /* data sent from gdbreplay to gdb, play it */
560 play (fp);
561 break;
562 case 'c':
563 /* We want to always print the command executed by GDB. */
564 if (!debug_logging)
566 fprintf (stderr, "\n");
567 fprintf (stderr, "Command expected from GDB:\n");
569 while ((ch = logchar (fp, true)) != EOL);
570 break;
571 case 'E':
572 if (!debug_logging)
573 fprintf (stderr, "E");
574 while ((ch = logchar (fp, true)) != EOL);
575 break;
578 remote_close ();
579 exit (0);
583 main (int argc, char *argv[])
587 captured_main (argc, argv);
589 catch (const gdb_exception &exception)
591 if (exception.reason == RETURN_ERROR)
593 fflush (stdout);
594 fprintf (stderr, "%s\n", exception.what ());
597 exit (1);
600 gdb_assert_not_reached ("captured_main should never return");