2012-03-08 Stan Shebs <stan@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / gdbserver / gdbreplay.c
CommitLineData
c906108c 1/* Replay a remote debug session logfile for GDB.
28e7fd62 2 Copyright (C) 1996-2013 Free Software Foundation, Inc.
c906108c
SS
3 Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.
4
c5aa993b 5 This file is part of GDB.
c906108c 6
c5aa993b
JM
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
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
c5aa993b 10 (at your option) any later version.
c906108c 11
c5aa993b
JM
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.
c906108c 16
c5aa993b 17 You should have received a copy of the GNU General Public License
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c 19
5c44784c 20#include "config.h"
406b1477
KS
21#include "build-gnulib-gdbserver/config.h"
22
c906108c 23#include <stdio.h>
68070c10 24#if HAVE_SYS_FILE_H
c906108c 25#include <sys/file.h>
68070c10
PA
26#endif
27#if HAVE_SIGNAL_H
c906108c 28#include <signal.h>
68070c10 29#endif
c906108c 30#include <ctype.h>
68070c10 31#if HAVE_FCNTL_H
c906108c 32#include <fcntl.h>
68070c10
PA
33#endif
34#if HAVE_ERRNO_H
5c44784c 35#include <errno.h>
68070c10 36#endif
82e0fd98
DB
37#ifdef HAVE_STDLIB_H
38#include <stdlib.h>
39#endif
0729219d
DJ
40#ifdef HAVE_STRING_H
41#include <string.h>
42#endif
82e0fd98
DB
43#ifdef HAVE_UNISTD_H
44#include <unistd.h>
45#endif
b80864fb
DJ
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
a778ab81 58#if HAVE_ALLOCA_H
59#include <alloca.h>
60#endif
68070c10
PA
61#if HAVE_MALLOC_H
62#include <malloc.h>
63#endif
b80864fb 64#if USE_WIN32API
12ea4b69 65#include <winsock2.h>
b80864fb 66#endif
c906108c 67
f450004a
DJ
68#ifndef HAVE_SOCKLEN_T
69typedef int socklen_t;
70#endif
71
c906108c
SS
72/* Sort of a hack... */
73#define EOL (EOF - 1)
74
c16158bc
JM
75/* Version information, from version.c. */
76extern const char version[];
77extern const char host_name[];
78
c906108c
SS
79static int remote_desc;
80
68070c10
PA
81#ifdef __MINGW32CE__
82
83#ifndef COUNTOF
84#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0]))
85#endif
86
87#define errno (GetLastError ())
88
89char *
90strerror (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
c906108c
SS
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
82e0fd98 136static void
54363045 137perror_with_name (const char *string)
c906108c 138{
5c44784c 139#ifndef STDC_HEADERS
c906108c 140 extern int errno;
5c44784c
JM
141#endif
142 const char *err;
c906108c
SS
143 char *combined;
144
43d5792c
DJ
145 err = strerror (errno);
146 if (err == NULL)
147 err = "unknown error";
148
c906108c
SS
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
158static void
fba45db2 159sync_error (FILE *fp, char *desc, int expect, int got)
c906108c
SS
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
e581f2b4
PA
168static void
169remote_error (const char *desc)
170{
171 fprintf (stderr, "\n%s\n", desc);
172 fflush (stderr);
173 exit (1);
174}
175
82e0fd98 176static void
fba45db2 177remote_close (void)
c906108c 178{
b80864fb
DJ
179#ifdef USE_WIN32API
180 closesocket (remote_desc);
181#else
c906108c 182 close (remote_desc);
b80864fb 183#endif
c906108c
SS
184}
185
186/* Open a connection to a remote debugger.
187 NAME is the filename used for communication. */
188
82e0fd98 189static void
fba45db2 190remote_open (char *name)
c906108c 191{
c906108c
SS
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 {
b80864fb
DJ
200#ifdef USE_WIN32API
201 static int winsock_initialized;
202#endif
c906108c
SS
203 char *port_str;
204 int port;
205 struct sockaddr_in sockaddr;
f450004a 206 socklen_t tmp;
c906108c
SS
207 int tmp_desc;
208
209 port_str = strchr (name, ':');
210
211 port = atoi (port_str + 1);
212
b80864fb
DJ
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
c906108c 223 tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
363a6e9f 224 if (tmp_desc == -1)
c906108c
SS
225 perror_with_name ("Can't open socket");
226
227 /* Allow rapid reuse of this port. */
228 tmp = 1;
c5aa993b
JM
229 setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
230 sizeof (tmp));
c906108c
SS
231
232 sockaddr.sin_family = PF_INET;
c5aa993b 233 sockaddr.sin_port = htons (port);
c906108c
SS
234 sockaddr.sin_addr.s_addr = INADDR_ANY;
235
c5aa993b 236 if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
c906108c
SS
237 || listen (tmp_desc, 1))
238 perror_with_name ("Can't bind address");
239
240 tmp = sizeof (sockaddr);
c5aa993b 241 remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
c906108c
SS
242 if (remote_desc == -1)
243 perror_with_name ("Accept failed");
244
c906108c
SS
245 /* Enable TCP keep alive process. */
246 tmp = 1;
493e2a69
MS
247 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE,
248 (char *) &tmp, sizeof (tmp));
c906108c
SS
249
250 /* Tell TCP not to delay small packets. This greatly speeds up
1b3f6016 251 interactive response. */
c906108c 252 tmp = 1;
373fe97f 253 setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
c5aa993b 254 (char *) &tmp, sizeof (tmp));
c906108c 255
b80864fb
DJ
256#ifndef USE_WIN32API
257 close (tmp_desc); /* No longer need this */
258
493e2a69
MS
259 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then
260 gdbreplay simply exits when
261 the remote side dies. */
b80864fb
DJ
262#else
263 closesocket (tmp_desc); /* No longer need this */
264#endif
c906108c
SS
265 }
266
b80864fb 267#if defined(F_SETFL) && defined (FASYNC)
c906108c 268 fcntl (remote_desc, F_SETFL, FASYNC);
b80864fb 269#endif
c906108c
SS
270
271 fprintf (stderr, "Replay logfile using %s\n", name);
272 fflush (stderr);
273}
274
c5aa993b 275static int
fba45db2 276tohex (int ch)
c906108c
SS
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
295static int
fba45db2 296logchar (FILE *fp)
c906108c
SS
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 {
c5aa993b
JM
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;
c906108c
SS
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
e581f2b4
PA
355static int
356gdbchar (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
c906108c
SS
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
82e0fd98 369static void
fba45db2 370expect (FILE *fp)
c906108c
SS
371{
372 int fromlog;
e581f2b4 373 int fromgdb;
c906108c
SS
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)
e581f2b4
PA
384 break;
385 fromgdb = gdbchar (remote_desc);
386 if (fromgdb < 0)
387 remote_error ("Error during read from gdb");
c5aa993b
JM
388 }
389 while (fromlog == fromgdb);
e581f2b4 390
c906108c
SS
391 if (fromlog != EOL)
392 {
e581f2b4 393 sync_error (fp, "Sync error during read of gdb packet from log", fromlog,
c906108c
SS
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
82e0fd98 401static void
fba45db2 402play (FILE *fp)
c906108c
SS
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;
e581f2b4
PA
415 if (write (remote_desc, &ch, 1) != 1)
416 remote_error ("Error during write to gdb");
c906108c
SS
417 }
418}
419
c16158bc
JM
420static void
421gdbreplay_version (void)
422{
423 printf ("GNU gdbreplay %s%s\n"
b9786c74 424 "Copyright (C) 2013 Free Software Foundation, Inc.\n"
493e2a69
MS
425 "gdbreplay is free software, covered by "
426 "the GNU General Public License.\n"
90aa6a40 427 "This gdbreplay was configured as \"%s\"\n",
c16158bc
JM
428 PKGVERSION, version, host_name);
429}
430
431static void
432gdbreplay_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
c906108c 439int
da85418c 440main (int argc, char *argv[])
c906108c
SS
441{
442 FILE *fp;
443 int ch;
444
c16158bc
JM
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
c906108c
SS
456 if (argc < 3)
457 {
c16158bc 458 gdbreplay_usage (stderr);
c906108c
SS
459 exit (1);
460 }
461 fp = fopen (argv[1], "r");
462 if (fp == NULL)
463 {
464 perror_with_name (argv[1]);
c5aa993b 465 }
c906108c
SS
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}
This page took 0.951965 seconds and 4 git commands to generate.