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