gdb/gdbserver/gdbreplay.c - gdb

Global variables defined

Data types defined

Functions defined

Macros defined

Source code

  1. /* Replay a remote debug session logfile for GDB.
  2.    Copyright (C) 1996-2015 Free Software Foundation, Inc.
  3.    Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.

  4.    This file is part of GDB.

  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 3 of the License, or
  8.    (at your option) any later version.

  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.

  13.    You should have received a copy of the GNU General Public License
  14.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  15. #include "config.h"
  16. #include "build-gnulib-gdbserver/config.h"
  17. #include "version.h"

  18. #include <stdio.h>
  19. #if HAVE_SYS_FILE_H
  20. #include <sys/file.h>
  21. #endif
  22. #if HAVE_SIGNAL_H
  23. #include <signal.h>
  24. #endif
  25. #include <ctype.h>
  26. #if HAVE_FCNTL_H
  27. #include <fcntl.h>
  28. #endif
  29. #include <errno.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <unistd.h>
  33. #ifdef HAVE_NETINET_IN_H
  34. #include <netinet/in.h>
  35. #endif
  36. #ifdef HAVE_SYS_SOCKET_H
  37. #include <sys/socket.h>
  38. #endif
  39. #if HAVE_NETDB_H
  40. #include <netdb.h>
  41. #endif
  42. #if HAVE_NETINET_TCP_H
  43. #include <netinet/tcp.h>
  44. #endif

  45. #include <alloca.h>

  46. #if USE_WIN32API
  47. #include <winsock2.h>
  48. #endif

  49. #ifndef HAVE_SOCKLEN_T
  50. typedef int socklen_t;
  51. #endif

  52. /* Sort of a hack... */
  53. #define EOL (EOF - 1)

  54. static int remote_desc;

  55. #ifdef __MINGW32CE__

  56. #ifndef COUNTOF
  57. #define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0]))
  58. #endif

  59. #define errno (GetLastError ())

  60. char *
  61. strerror (DWORD error)
  62. {
  63.   static char buf[1024];
  64.   WCHAR *msgbuf;
  65.   DWORD lasterr = GetLastError ();
  66.   DWORD chars = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM
  67.                                 | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  68.                                 NULL,
  69.                                 error,
  70.                                 0, /* Default language */
  71.                                 (LPVOID)&msgbuf,
  72.                                 0,
  73.                                 NULL);
  74.   if (chars != 0)
  75.     {
  76.       /* If there is an \r\n appended, zap it.  */
  77.       if (chars >= 2
  78.           && msgbuf[chars - 2] == '\r'
  79.           && msgbuf[chars - 1] == '\n')
  80.         {
  81.           chars -= 2;
  82.           msgbuf[chars] = 0;
  83.         }

  84.       if (chars > ((COUNTOF (buf)) - 1))
  85.         {
  86.           chars = COUNTOF (buf) - 1;
  87.           msgbuf [chars] = 0;
  88.         }

  89.       wcstombs (buf, msgbuf, chars + 1);
  90.       LocalFree (msgbuf);
  91.     }
  92.   else
  93.     sprintf (buf, "unknown win32 error (%ld)", error);

  94.   SetLastError (lasterr);
  95.   return buf;
  96. }

  97. #endif /* __MINGW32CE__ */

  98. /* Print the system error message for errno, and also mention STRING
  99.    as the file name for which the error was encountered.
  100.    Then return to command level.  */

  101. static void
  102. perror_with_name (const char *string)
  103. {
  104. #ifndef STDC_HEADERS
  105.   extern int errno;
  106. #endif
  107.   const char *err;
  108.   char *combined;

  109.   err = strerror (errno);
  110.   if (err == NULL)
  111.     err = "unknown error";

  112.   combined = (char *) alloca (strlen (err) + strlen (string) + 3);
  113.   strcpy (combined, string);
  114.   strcat (combined, ": ");
  115.   strcat (combined, err);
  116.   fprintf (stderr, "\n%s.\n", combined);
  117.   fflush (stderr);
  118.   exit (1);
  119. }

  120. static void
  121. sync_error (FILE *fp, char *desc, int expect, int got)
  122. {
  123.   fprintf (stderr, "\n%s\n", desc);
  124.   fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
  125.            ftell (fp), expect, got);
  126.   fflush (stderr);
  127.   exit (1);
  128. }

  129. static void
  130. remote_error (const char *desc)
  131. {
  132.   fprintf (stderr, "\n%s\n", desc);
  133.   fflush (stderr);
  134.   exit (1);
  135. }

  136. static void
  137. remote_close (void)
  138. {
  139. #ifdef USE_WIN32API
  140.   closesocket (remote_desc);
  141. #else
  142.   close (remote_desc);
  143. #endif
  144. }

  145. /* Open a connection to a remote debugger.
  146.    NAME is the filename used for communication.  */

  147. static void
  148. remote_open (char *name)
  149. {
  150.   if (!strchr (name, ':'))
  151.     {
  152.       fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
  153.       fflush (stderr);
  154.       exit (1);
  155.     }
  156.   else
  157.     {
  158. #ifdef USE_WIN32API
  159.       static int winsock_initialized;
  160. #endif
  161.       char *port_str;
  162.       int port;
  163.       struct sockaddr_in sockaddr;
  164.       socklen_t tmp;
  165.       int tmp_desc;

  166.       port_str = strchr (name, ':');

  167.       port = atoi (port_str + 1);

  168. #ifdef USE_WIN32API
  169.       if (!winsock_initialized)
  170.         {
  171.           WSADATA wsad;

  172.           WSAStartup (MAKEWORD (1, 0), &wsad);
  173.           winsock_initialized = 1;
  174.         }
  175. #endif

  176.       tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
  177.       if (tmp_desc == -1)
  178.         perror_with_name ("Can't open socket");

  179.       /* Allow rapid reuse of this port. */
  180.       tmp = 1;
  181.       setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
  182.                   sizeof (tmp));

  183.       sockaddr.sin_family = PF_INET;
  184.       sockaddr.sin_port = htons (port);
  185.       sockaddr.sin_addr.s_addr = INADDR_ANY;

  186.       if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
  187.           || listen (tmp_desc, 1))
  188.         perror_with_name ("Can't bind address");

  189.       tmp = sizeof (sockaddr);
  190.       remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
  191.       if (remote_desc == -1)
  192.         perror_with_name ("Accept failed");

  193.       /* Enable TCP keep alive process. */
  194.       tmp = 1;
  195.       setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE,
  196.                   (char *) &tmp, sizeof (tmp));

  197.       /* Tell TCP not to delay small packets.  This greatly speeds up
  198.          interactive response. */
  199.       tmp = 1;
  200.       setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
  201.                   (char *) &tmp, sizeof (tmp));

  202. #ifndef USE_WIN32API
  203.       close (tmp_desc);                /* No longer need this */

  204.       signal (SIGPIPE, SIG_IGN);        /* If we don't do this, then
  205.                                            gdbreplay simply exits when
  206.                                            the remote side dies.  */
  207. #else
  208.       closesocket (tmp_desc);        /* No longer need this */
  209. #endif
  210.     }

  211. #if defined(F_SETFL) && defined (FASYNC)
  212.   fcntl (remote_desc, F_SETFL, FASYNC);
  213. #endif

  214.   fprintf (stderr, "Replay logfile using %s\n", name);
  215.   fflush (stderr);
  216. }

  217. static int
  218. tohex (int ch)
  219. {
  220.   if (ch >= '0' && ch <= '9')
  221.     {
  222.       return (ch - '0');
  223.     }
  224.   if (ch >= 'A' && ch <= 'F')
  225.     {
  226.       return (ch - 'A' + 10);
  227.     }
  228.   if (ch >= 'a' && ch <= 'f')
  229.     {
  230.       return (ch - 'a' + 10);
  231.     }
  232.   fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
  233.   fflush (stderr);
  234.   exit (1);
  235. }

  236. static int
  237. logchar (FILE *fp)
  238. {
  239.   int ch;
  240.   int ch2;

  241.   ch = fgetc (fp);
  242.   fputc (ch, stdout);
  243.   fflush (stdout);
  244.   switch (ch)
  245.     {
  246.     case '\n':
  247.       ch = EOL;
  248.       break;
  249.     case '\\':
  250.       ch = fgetc (fp);
  251.       fputc (ch, stdout);
  252.       fflush (stdout);
  253.       switch (ch)
  254.         {
  255.         case '\\':
  256.           break;
  257.         case 'b':
  258.           ch = '\b';
  259.           break;
  260.         case 'f':
  261.           ch = '\f';
  262.           break;
  263.         case 'n':
  264.           ch = '\n';
  265.           break;
  266.         case 'r':
  267.           ch = '\r';
  268.           break;
  269.         case 't':
  270.           ch = '\t';
  271.           break;
  272.         case 'v':
  273.           ch = '\v';
  274.           break;
  275.         case 'x':
  276.           ch2 = fgetc (fp);
  277.           fputc (ch2, stdout);
  278.           fflush (stdout);
  279.           ch = tohex (ch2) << 4;
  280.           ch2 = fgetc (fp);
  281.           fputc (ch2, stdout);
  282.           fflush (stdout);
  283.           ch |= tohex (ch2);
  284.           break;
  285.         default:
  286.           /* Treat any other char as just itself */
  287.           break;
  288.         }
  289.     default:
  290.       break;
  291.     }
  292.   return (ch);
  293. }

  294. static int
  295. gdbchar (int desc)
  296. {
  297.   unsigned char fromgdb;

  298.   if (read (desc, &fromgdb, 1) != 1)
  299.     return -1;
  300.   else
  301.     return fromgdb;
  302. }

  303. /* Accept input from gdb and match with chars from fp (after skipping one
  304.    blank) up until a \n is read from fp (which is not matched) */

  305. static void
  306. expect (FILE *fp)
  307. {
  308.   int fromlog;
  309.   int fromgdb;

  310.   if ((fromlog = logchar (fp)) != ' ')
  311.     {
  312.       sync_error (fp, "Sync error during gdb read of leading blank", ' ',
  313.                   fromlog);
  314.     }
  315.   do
  316.     {
  317.       fromlog = logchar (fp);
  318.       if (fromlog == EOL)
  319.         break;
  320.       fromgdb = gdbchar (remote_desc);
  321.       if (fromgdb < 0)
  322.         remote_error ("Error during read from gdb");
  323.     }
  324.   while (fromlog == fromgdb);

  325.   if (fromlog != EOL)
  326.     {
  327.       sync_error (fp, "Sync error during read of gdb packet from log", fromlog,
  328.                   fromgdb);
  329.     }
  330. }

  331. /* Play data back to gdb from fp (after skipping leading blank) up until a
  332.    \n is read from fp (which is discarded and not sent to gdb). */

  333. static void
  334. play (FILE *fp)
  335. {
  336.   int fromlog;
  337.   char ch;

  338.   if ((fromlog = logchar (fp)) != ' ')
  339.     {
  340.       sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
  341.                   fromlog);
  342.     }
  343.   while ((fromlog = logchar (fp)) != EOL)
  344.     {
  345.       ch = fromlog;
  346.       if (write (remote_desc, &ch, 1) != 1)
  347.         remote_error ("Error during write to gdb");
  348.     }
  349. }

  350. static void
  351. gdbreplay_version (void)
  352. {
  353.   printf ("GNU gdbreplay %s%s\n"
  354.           "Copyright (C) 2015 Free Software Foundation, Inc.\n"
  355.           "gdbreplay is free software, covered by "
  356.           "the GNU General Public License.\n"
  357.           "This gdbreplay was configured as \"%s\"\n",
  358.           PKGVERSION, version, host_name);
  359. }

  360. static void
  361. gdbreplay_usage (FILE *stream)
  362. {
  363.   fprintf (stream, "Usage:\tgdbreplay <logfile> <host:port>\n");
  364.   if (REPORT_BUGS_TO[0] && stream == stdout)
  365.     fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO);
  366. }

  367. int
  368. main (int argc, char *argv[])
  369. {
  370.   FILE *fp;
  371.   int ch;

  372.   if (argc >= 2 && strcmp (argv[1], "--version") == 0)
  373.     {
  374.       gdbreplay_version ();
  375.       exit (0);
  376.     }
  377.   if (argc >= 2 && strcmp (argv[1], "--help") == 0)
  378.     {
  379.       gdbreplay_usage (stdout);
  380.       exit (0);
  381.     }

  382.   if (argc < 3)
  383.     {
  384.       gdbreplay_usage (stderr);
  385.       exit (1);
  386.     }
  387.   fp = fopen (argv[1], "r");
  388.   if (fp == NULL)
  389.     {
  390.       perror_with_name (argv[1]);
  391.     }
  392.   remote_open (argv[2]);
  393.   while ((ch = logchar (fp)) != EOF)
  394.     {
  395.       switch (ch)
  396.         {
  397.         case 'w':
  398.           /* data sent from gdb to gdbreplay, accept and match it */
  399.           expect (fp);
  400.           break;
  401.         case 'r':
  402.           /* data sent from gdbreplay to gdb, play it */
  403.           play (fp);
  404.           break;
  405.         case 'c':
  406.           /* Command executed by gdb */
  407.           while ((ch = logchar (fp)) != EOL);
  408.           break;
  409.         }
  410.     }
  411.   remote_close ();
  412.   exit (0);
  413. }