Update years in copyright notice for the GDB files.
[external/binutils.git] / gdb / gdbserver / gdbreplay.c
1 /* Replay a remote debug session logfile for GDB.
2    Copyright (C) 1996-2013 Free Software Foundation, Inc.
3    Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.
4
5    This file is part of GDB.
6
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.
11
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.
16
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/>.  */
19
20 #include "config.h"
21 #include "build-gnulib-gdbserver/config.h"
22
23 #include <stdio.h>
24 #if HAVE_SYS_FILE_H
25 #include <sys/file.h>
26 #endif
27 #if HAVE_SIGNAL_H
28 #include <signal.h>
29 #endif
30 #include <ctype.h>
31 #if HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34 #if HAVE_ERRNO_H
35 #include <errno.h>
36 #endif
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46 #ifdef HAVE_NETINET_IN_H
47 #include <netinet/in.h>
48 #endif
49 #ifdef HAVE_SYS_SOCKET_H
50 #include <sys/socket.h>
51 #endif
52 #if HAVE_NETDB_H
53 #include <netdb.h>
54 #endif
55 #if HAVE_NETINET_TCP_H
56 #include <netinet/tcp.h>
57 #endif
58 #if HAVE_ALLOCA_H
59 #include <alloca.h>
60 #endif
61 #if HAVE_MALLOC_H
62 #include <malloc.h>
63 #endif
64 #if USE_WIN32API
65 #include <winsock2.h>
66 #endif
67
68 #ifndef HAVE_SOCKLEN_T
69 typedef int socklen_t;
70 #endif
71
72 /* Sort of a hack... */
73 #define EOL (EOF - 1)
74
75 /* Version information, from version.c.  */
76 extern const char version[];
77 extern const char host_name[];
78
79 static int remote_desc;
80
81 #ifdef __MINGW32CE__
82
83 #ifndef COUNTOF
84 #define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0]))
85 #endif
86
87 #define errno (GetLastError ())
88
89 char *
90 strerror (DWORD error)
91 {
92   static char buf[1024];
93   WCHAR *msgbuf;
94   DWORD lasterr = GetLastError ();
95   DWORD chars = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM
96                                 | FORMAT_MESSAGE_ALLOCATE_BUFFER,
97                                 NULL,
98                                 error,
99                                 0, /* Default language */
100                                 (LPVOID)&msgbuf,
101                                 0,
102                                 NULL);
103   if (chars != 0)
104     {
105       /* If there is an \r\n appended, zap it.  */
106       if (chars >= 2
107           && msgbuf[chars - 2] == '\r'
108           && msgbuf[chars - 1] == '\n')
109         {
110           chars -= 2;
111           msgbuf[chars] = 0;
112         }
113
114       if (chars > ((COUNTOF (buf)) - 1))
115         {
116           chars = COUNTOF (buf) - 1;
117           msgbuf [chars] = 0;
118         }
119
120       wcstombs (buf, msgbuf, chars + 1);
121       LocalFree (msgbuf);
122     }
123   else
124     sprintf (buf, "unknown win32 error (%ld)", error);
125
126   SetLastError (lasterr);
127   return buf;
128 }
129
130 #endif /* __MINGW32CE__ */
131
132 /* Print the system error message for errno, and also mention STRING
133    as the file name for which the error was encountered.
134    Then return to command level.  */
135
136 static void
137 perror_with_name (const char *string)
138 {
139 #ifndef STDC_HEADERS
140   extern int errno;
141 #endif
142   const char *err;
143   char *combined;
144
145   err = strerror (errno);
146   if (err == NULL)
147     err = "unknown error";
148
149   combined = (char *) alloca (strlen (err) + strlen (string) + 3);
150   strcpy (combined, string);
151   strcat (combined, ": ");
152   strcat (combined, err);
153   fprintf (stderr, "\n%s.\n", combined);
154   fflush (stderr);
155   exit (1);
156 }
157
158 static void
159 sync_error (FILE *fp, char *desc, int expect, int got)
160 {
161   fprintf (stderr, "\n%s\n", desc);
162   fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
163            ftell (fp), expect, got);
164   fflush (stderr);
165   exit (1);
166 }
167
168 static void
169 remote_error (const char *desc)
170 {
171   fprintf (stderr, "\n%s\n", desc);
172   fflush (stderr);
173   exit (1);
174 }
175
176 static void
177 remote_close (void)
178 {
179 #ifdef USE_WIN32API
180   closesocket (remote_desc);
181 #else
182   close (remote_desc);
183 #endif
184 }
185
186 /* Open a connection to a remote debugger.
187    NAME is the filename used for communication.  */
188
189 static void
190 remote_open (char *name)
191 {
192   if (!strchr (name, ':'))
193     {
194       fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
195       fflush (stderr);
196       exit (1);
197     }
198   else
199     {
200 #ifdef USE_WIN32API
201       static int winsock_initialized;
202 #endif
203       char *port_str;
204       int port;
205       struct sockaddr_in sockaddr;
206       socklen_t tmp;
207       int tmp_desc;
208
209       port_str = strchr (name, ':');
210
211       port = atoi (port_str + 1);
212
213 #ifdef USE_WIN32API
214       if (!winsock_initialized)
215         {
216           WSADATA wsad;
217
218           WSAStartup (MAKEWORD (1, 0), &wsad);
219           winsock_initialized = 1;
220         }
221 #endif
222
223       tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
224       if (tmp_desc == -1)
225         perror_with_name ("Can't open socket");
226
227       /* Allow rapid reuse of this port. */
228       tmp = 1;
229       setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
230                   sizeof (tmp));
231
232       sockaddr.sin_family = PF_INET;
233       sockaddr.sin_port = htons (port);
234       sockaddr.sin_addr.s_addr = INADDR_ANY;
235
236       if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
237           || listen (tmp_desc, 1))
238         perror_with_name ("Can't bind address");
239
240       tmp = sizeof (sockaddr);
241       remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
242       if (remote_desc == -1)
243         perror_with_name ("Accept failed");
244
245       /* Enable TCP keep alive process. */
246       tmp = 1;
247       setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE,
248                   (char *) &tmp, sizeof (tmp));
249
250       /* Tell TCP not to delay small packets.  This greatly speeds up
251          interactive response. */
252       tmp = 1;
253       setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
254                   (char *) &tmp, sizeof (tmp));
255
256 #ifndef USE_WIN32API
257       close (tmp_desc);         /* No longer need this */
258
259       signal (SIGPIPE, SIG_IGN);        /* If we don't do this, then
260                                            gdbreplay simply exits when
261                                            the remote side dies.  */
262 #else
263       closesocket (tmp_desc);   /* No longer need this */
264 #endif
265     }
266
267 #if defined(F_SETFL) && defined (FASYNC)
268   fcntl (remote_desc, F_SETFL, FASYNC);
269 #endif
270
271   fprintf (stderr, "Replay logfile using %s\n", name);
272   fflush (stderr);
273 }
274
275 static int
276 tohex (int ch)
277 {
278   if (ch >= '0' && ch <= '9')
279     {
280       return (ch - '0');
281     }
282   if (ch >= 'A' && ch <= 'F')
283     {
284       return (ch - 'A' + 10);
285     }
286   if (ch >= 'a' && ch <= 'f')
287     {
288       return (ch - 'a' + 10);
289     }
290   fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
291   fflush (stderr);
292   exit (1);
293 }
294
295 static int
296 logchar (FILE *fp)
297 {
298   int ch;
299   int ch2;
300
301   ch = fgetc (fp);
302   fputc (ch, stdout);
303   fflush (stdout);
304   switch (ch)
305     {
306     case '\n':
307       ch = EOL;
308       break;
309     case '\\':
310       ch = fgetc (fp);
311       fputc (ch, stdout);
312       fflush (stdout);
313       switch (ch)
314         {
315         case '\\':
316           break;
317         case 'b':
318           ch = '\b';
319           break;
320         case 'f':
321           ch = '\f';
322           break;
323         case 'n':
324           ch = '\n';
325           break;
326         case 'r':
327           ch = '\r';
328           break;
329         case 't':
330           ch = '\t';
331           break;
332         case 'v':
333           ch = '\v';
334           break;
335         case 'x':
336           ch2 = fgetc (fp);
337           fputc (ch2, stdout);
338           fflush (stdout);
339           ch = tohex (ch2) << 4;
340           ch2 = fgetc (fp);
341           fputc (ch2, stdout);
342           fflush (stdout);
343           ch |= tohex (ch2);
344           break;
345         default:
346           /* Treat any other char as just itself */
347           break;
348         }
349     default:
350       break;
351     }
352   return (ch);
353 }
354
355 static int
356 gdbchar (int desc)
357 {
358   unsigned char fromgdb;
359
360   if (read (desc, &fromgdb, 1) != 1)
361     return -1;
362   else
363     return fromgdb;
364 }
365
366 /* Accept input from gdb and match with chars from fp (after skipping one
367    blank) up until a \n is read from fp (which is not matched) */
368
369 static void
370 expect (FILE *fp)
371 {
372   int fromlog;
373   int fromgdb;
374
375   if ((fromlog = logchar (fp)) != ' ')
376     {
377       sync_error (fp, "Sync error during gdb read of leading blank", ' ',
378                   fromlog);
379     }
380   do
381     {
382       fromlog = logchar (fp);
383       if (fromlog == EOL)
384         break;
385       fromgdb = gdbchar (remote_desc);
386       if (fromgdb < 0)
387         remote_error ("Error during read from gdb");
388     }
389   while (fromlog == fromgdb);
390
391   if (fromlog != EOL)
392     {
393       sync_error (fp, "Sync error during read of gdb packet from log", fromlog,
394                   fromgdb);
395     }
396 }
397
398 /* Play data back to gdb from fp (after skipping leading blank) up until a
399    \n is read from fp (which is discarded and not sent to gdb). */
400
401 static void
402 play (FILE *fp)
403 {
404   int fromlog;
405   char ch;
406
407   if ((fromlog = logchar (fp)) != ' ')
408     {
409       sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
410                   fromlog);
411     }
412   while ((fromlog = logchar (fp)) != EOL)
413     {
414       ch = fromlog;
415       if (write (remote_desc, &ch, 1) != 1)
416         remote_error ("Error during write to gdb");
417     }
418 }
419
420 static void
421 gdbreplay_version (void)
422 {
423   printf ("GNU gdbreplay %s%s\n"
424           "Copyright (C) 2013 Free Software Foundation, Inc.\n"
425           "gdbreplay is free software, covered by "
426           "the GNU General Public License.\n"
427           "This gdbreplay was configured as \"%s\"\n",
428           PKGVERSION, version, host_name);
429 }
430
431 static void
432 gdbreplay_usage (FILE *stream)
433 {
434   fprintf (stream, "Usage:\tgdbreplay <logfile> <host:port>\n");
435   if (REPORT_BUGS_TO[0] && stream == stdout)
436     fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO);
437 }
438
439 int
440 main (int argc, char *argv[])
441 {
442   FILE *fp;
443   int ch;
444
445   if (argc >= 2 && strcmp (argv[1], "--version") == 0)
446     {
447       gdbreplay_version ();
448       exit (0);
449     }
450   if (argc >= 2 && strcmp (argv[1], "--help") == 0)
451     {
452       gdbreplay_usage (stdout);
453       exit (0);
454     }
455
456   if (argc < 3)
457     {
458       gdbreplay_usage (stderr);
459       exit (1);
460     }
461   fp = fopen (argv[1], "r");
462   if (fp == NULL)
463     {
464       perror_with_name (argv[1]);
465     }
466   remote_open (argv[2]);
467   while ((ch = logchar (fp)) != EOF)
468     {
469       switch (ch)
470         {
471         case 'w':
472           /* data sent from gdb to gdbreplay, accept and match it */
473           expect (fp);
474           break;
475         case 'r':
476           /* data sent from gdbreplay to gdb, play it */
477           play (fp);
478           break;
479         case 'c':
480           /* Command executed by gdb */
481           while ((ch = logchar (fp)) != EOL);
482           break;
483         }
484     }
485   remote_close ();
486   exit (0);
487 }