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