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