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