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