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