[NEWS] Announce support for PowerPC LynxOS 5.x.
[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,
4c38e0a4 3 2009, 2010 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;
c5aa993b 246 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
c906108c
SS
247
248 /* Tell TCP not to delay small packets. This greatly speeds up
1b3f6016 249 interactive response. */
c906108c 250 tmp = 1;
373fe97f 251 setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
c5aa993b 252 (char *) &tmp, sizeof (tmp));
c906108c 253
b80864fb
DJ
254#ifndef USE_WIN32API
255 close (tmp_desc); /* No longer need this */
256
c5aa993b
JM
257 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply
258 exits when the remote side dies. */
b80864fb
DJ
259#else
260 closesocket (tmp_desc); /* No longer need this */
261#endif
c906108c
SS
262 }
263
b80864fb 264#if defined(F_SETFL) && defined (FASYNC)
c906108c 265 fcntl (remote_desc, F_SETFL, FASYNC);
b80864fb 266#endif
c906108c
SS
267
268 fprintf (stderr, "Replay logfile using %s\n", name);
269 fflush (stderr);
270}
271
c5aa993b 272static int
fba45db2 273tohex (int ch)
c906108c
SS
274{
275 if (ch >= '0' && ch <= '9')
276 {
277 return (ch - '0');
278 }
279 if (ch >= 'A' && ch <= 'F')
280 {
281 return (ch - 'A' + 10);
282 }
283 if (ch >= 'a' && ch <= 'f')
284 {
285 return (ch - 'a' + 10);
286 }
287 fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
288 fflush (stderr);
289 exit (1);
290}
291
292static int
fba45db2 293logchar (FILE *fp)
c906108c
SS
294{
295 int ch;
296 int ch2;
297
298 ch = fgetc (fp);
299 fputc (ch, stdout);
300 fflush (stdout);
301 switch (ch)
302 {
303 case '\n':
304 ch = EOL;
305 break;
306 case '\\':
307 ch = fgetc (fp);
308 fputc (ch, stdout);
309 fflush (stdout);
310 switch (ch)
311 {
c5aa993b
JM
312 case '\\':
313 break;
314 case 'b':
315 ch = '\b';
316 break;
317 case 'f':
318 ch = '\f';
319 break;
320 case 'n':
321 ch = '\n';
322 break;
323 case 'r':
324 ch = '\r';
325 break;
326 case 't':
327 ch = '\t';
328 break;
329 case 'v':
330 ch = '\v';
331 break;
c906108c
SS
332 case 'x':
333 ch2 = fgetc (fp);
334 fputc (ch2, stdout);
335 fflush (stdout);
336 ch = tohex (ch2) << 4;
337 ch2 = fgetc (fp);
338 fputc (ch2, stdout);
339 fflush (stdout);
340 ch |= tohex (ch2);
341 break;
342 default:
343 /* Treat any other char as just itself */
344 break;
345 }
346 default:
347 break;
348 }
349 return (ch);
350}
351
e581f2b4
PA
352static int
353gdbchar (int desc)
354{
355 unsigned char fromgdb;
356
357 if (read (desc, &fromgdb, 1) != 1)
358 return -1;
359 else
360 return fromgdb;
361}
362
c906108c
SS
363/* Accept input from gdb and match with chars from fp (after skipping one
364 blank) up until a \n is read from fp (which is not matched) */
365
82e0fd98 366static void
fba45db2 367expect (FILE *fp)
c906108c
SS
368{
369 int fromlog;
e581f2b4 370 int fromgdb;
c906108c
SS
371
372 if ((fromlog = logchar (fp)) != ' ')
373 {
374 sync_error (fp, "Sync error during gdb read of leading blank", ' ',
375 fromlog);
376 }
377 do
378 {
379 fromlog = logchar (fp);
380 if (fromlog == EOL)
e581f2b4
PA
381 break;
382 fromgdb = gdbchar (remote_desc);
383 if (fromgdb < 0)
384 remote_error ("Error during read from gdb");
c5aa993b
JM
385 }
386 while (fromlog == fromgdb);
e581f2b4 387
c906108c
SS
388 if (fromlog != EOL)
389 {
e581f2b4 390 sync_error (fp, "Sync error during read of gdb packet from log", fromlog,
c906108c
SS
391 fromgdb);
392 }
393}
394
395/* Play data back to gdb from fp (after skipping leading blank) up until a
396 \n is read from fp (which is discarded and not sent to gdb). */
397
82e0fd98 398static void
fba45db2 399play (FILE *fp)
c906108c
SS
400{
401 int fromlog;
402 char ch;
403
404 if ((fromlog = logchar (fp)) != ' ')
405 {
406 sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
407 fromlog);
408 }
409 while ((fromlog = logchar (fp)) != EOL)
410 {
411 ch = fromlog;
e581f2b4
PA
412 if (write (remote_desc, &ch, 1) != 1)
413 remote_error ("Error during write to gdb");
c906108c
SS
414 }
415}
416
c16158bc
JM
417static void
418gdbreplay_version (void)
419{
420 printf ("GNU gdbreplay %s%s\n"
6e7ffa39 421 "Copyright (C) 2010 Free Software Foundation, Inc.\n"
90aa6a40
JM
422 "gdbreplay is free software, covered by the GNU General Public License.\n"
423 "This gdbreplay was configured as \"%s\"\n",
c16158bc
JM
424 PKGVERSION, version, host_name);
425}
426
427static void
428gdbreplay_usage (FILE *stream)
429{
430 fprintf (stream, "Usage:\tgdbreplay <logfile> <host:port>\n");
431 if (REPORT_BUGS_TO[0] && stream == stdout)
432 fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO);
433}
434
c906108c 435int
da85418c 436main (int argc, char *argv[])
c906108c
SS
437{
438 FILE *fp;
439 int ch;
440
c16158bc
JM
441 if (argc >= 2 && strcmp (argv[1], "--version") == 0)
442 {
443 gdbreplay_version ();
444 exit (0);
445 }
446 if (argc >= 2 && strcmp (argv[1], "--help") == 0)
447 {
448 gdbreplay_usage (stdout);
449 exit (0);
450 }
451
c906108c
SS
452 if (argc < 3)
453 {
c16158bc 454 gdbreplay_usage (stderr);
c906108c
SS
455 exit (1);
456 }
457 fp = fopen (argv[1], "r");
458 if (fp == NULL)
459 {
460 perror_with_name (argv[1]);
c5aa993b 461 }
c906108c
SS
462 remote_open (argv[2]);
463 while ((ch = logchar (fp)) != EOF)
464 {
465 switch (ch)
466 {
467 case 'w':
468 /* data sent from gdb to gdbreplay, accept and match it */
469 expect (fp);
470 break;
471 case 'r':
472 /* data sent from gdbreplay to gdb, play it */
473 play (fp);
474 break;
475 case 'c':
476 /* Command executed by gdb */
477 while ((ch = logchar (fp)) != EOL);
478 break;
479 }
480 }
481 remote_close ();
482 exit (0);
483}
This page took 0.775707 seconds and 4 git commands to generate.