]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/gdbserver/gdbreplay.c
gdb/
[thirdparty/binutils-gdb.git] / gdb / gdbserver / gdbreplay.c
CommitLineData
c906108c 1/* Replay a remote debug session logfile for GDB.
b80864fb 2 Copyright (C) 1996, 1998, 1999, 2000, 2002, 2003, 2005, 2006
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
SS
24#include <stdio.h>
25#include <sys/file.h>
c906108c
SS
26#include <signal.h>
27#include <ctype.h>
28#include <fcntl.h>
5c44784c 29#include <errno.h>
0729219d 30
82e0fd98
DB
31#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
0729219d
DJ
34#ifdef HAVE_STRING_H
35#include <string.h>
36#endif
82e0fd98
DB
37#ifdef HAVE_UNISTD_H
38#include <unistd.h>
39#endif
b80864fb
DJ
40#ifdef HAVE_NETINET_IN_H
41#include <netinet/in.h>
42#endif
43#ifdef HAVE_SYS_SOCKET_H
44#include <sys/socket.h>
45#endif
46#if HAVE_NETDB_H
47#include <netdb.h>
48#endif
49#if HAVE_NETINET_TCP_H
50#include <netinet/tcp.h>
51#endif
52
53#if USE_WIN32API
54#include <winsock.h>
55#endif
c906108c 56
f450004a
DJ
57#ifndef HAVE_SOCKLEN_T
58typedef int socklen_t;
59#endif
60
c906108c
SS
61/* Sort of a hack... */
62#define EOL (EOF - 1)
63
64static int remote_desc;
65
66/* Print the system error message for errno, and also mention STRING
67 as the file name for which the error was encountered.
68 Then return to command level. */
69
82e0fd98 70static void
fba45db2 71perror_with_name (char *string)
c906108c 72{
5c44784c 73#ifndef STDC_HEADERS
c906108c 74 extern int errno;
5c44784c
JM
75#endif
76 const char *err;
c906108c
SS
77 char *combined;
78
43d5792c
DJ
79 err = strerror (errno);
80 if (err == NULL)
81 err = "unknown error";
82
c906108c
SS
83 combined = (char *) alloca (strlen (err) + strlen (string) + 3);
84 strcpy (combined, string);
85 strcat (combined, ": ");
86 strcat (combined, err);
87 fprintf (stderr, "\n%s.\n", combined);
88 fflush (stderr);
89 exit (1);
90}
91
92static void
fba45db2 93sync_error (FILE *fp, char *desc, int expect, int got)
c906108c
SS
94{
95 fprintf (stderr, "\n%s\n", desc);
96 fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
97 ftell (fp), expect, got);
98 fflush (stderr);
99 exit (1);
100}
101
82e0fd98 102static void
fba45db2 103remote_close (void)
c906108c 104{
b80864fb
DJ
105#ifdef USE_WIN32API
106 closesocket (remote_desc);
107#else
c906108c 108 close (remote_desc);
b80864fb 109#endif
c906108c
SS
110}
111
112/* Open a connection to a remote debugger.
113 NAME is the filename used for communication. */
114
82e0fd98 115static void
fba45db2 116remote_open (char *name)
c906108c 117{
c906108c
SS
118 if (!strchr (name, ':'))
119 {
120 fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
121 fflush (stderr);
122 exit (1);
123 }
124 else
125 {
b80864fb
DJ
126#ifdef USE_WIN32API
127 static int winsock_initialized;
128#endif
c906108c
SS
129 char *port_str;
130 int port;
131 struct sockaddr_in sockaddr;
f450004a 132 socklen_t tmp;
c906108c
SS
133 int tmp_desc;
134
135 port_str = strchr (name, ':');
136
137 port = atoi (port_str + 1);
138
b80864fb
DJ
139#ifdef USE_WIN32API
140 if (!winsock_initialized)
141 {
142 WSADATA wsad;
143
144 WSAStartup (MAKEWORD (1, 0), &wsad);
145 winsock_initialized = 1;
146 }
147#endif
148
c906108c
SS
149 tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
150 if (tmp_desc < 0)
151 perror_with_name ("Can't open socket");
152
153 /* Allow rapid reuse of this port. */
154 tmp = 1;
c5aa993b
JM
155 setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
156 sizeof (tmp));
c906108c
SS
157
158 sockaddr.sin_family = PF_INET;
c5aa993b 159 sockaddr.sin_port = htons (port);
c906108c
SS
160 sockaddr.sin_addr.s_addr = INADDR_ANY;
161
c5aa993b 162 if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
c906108c
SS
163 || listen (tmp_desc, 1))
164 perror_with_name ("Can't bind address");
165
166 tmp = sizeof (sockaddr);
c5aa993b 167 remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
c906108c
SS
168 if (remote_desc == -1)
169 perror_with_name ("Accept failed");
170
c906108c
SS
171 /* Enable TCP keep alive process. */
172 tmp = 1;
c5aa993b 173 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
c906108c
SS
174
175 /* Tell TCP not to delay small packets. This greatly speeds up
c5aa993b 176 interactive response. */
c906108c 177 tmp = 1;
373fe97f 178 setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
c5aa993b 179 (char *) &tmp, sizeof (tmp));
c906108c
SS
180
181 close (tmp_desc); /* No longer need this */
182
b80864fb
DJ
183#ifndef USE_WIN32API
184 close (tmp_desc); /* No longer need this */
185
c5aa993b
JM
186 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply
187 exits when the remote side dies. */
b80864fb
DJ
188#else
189 closesocket (tmp_desc); /* No longer need this */
190#endif
c906108c
SS
191 }
192
b80864fb 193#if defined(F_SETFL) && defined (FASYNC)
c906108c 194 fcntl (remote_desc, F_SETFL, FASYNC);
b80864fb 195#endif
c906108c
SS
196
197 fprintf (stderr, "Replay logfile using %s\n", name);
198 fflush (stderr);
199}
200
c5aa993b 201static int
fba45db2 202tohex (int ch)
c906108c
SS
203{
204 if (ch >= '0' && ch <= '9')
205 {
206 return (ch - '0');
207 }
208 if (ch >= 'A' && ch <= 'F')
209 {
210 return (ch - 'A' + 10);
211 }
212 if (ch >= 'a' && ch <= 'f')
213 {
214 return (ch - 'a' + 10);
215 }
216 fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
217 fflush (stderr);
218 exit (1);
219}
220
221static int
fba45db2 222logchar (FILE *fp)
c906108c
SS
223{
224 int ch;
225 int ch2;
226
227 ch = fgetc (fp);
228 fputc (ch, stdout);
229 fflush (stdout);
230 switch (ch)
231 {
232 case '\n':
233 ch = EOL;
234 break;
235 case '\\':
236 ch = fgetc (fp);
237 fputc (ch, stdout);
238 fflush (stdout);
239 switch (ch)
240 {
c5aa993b
JM
241 case '\\':
242 break;
243 case 'b':
244 ch = '\b';
245 break;
246 case 'f':
247 ch = '\f';
248 break;
249 case 'n':
250 ch = '\n';
251 break;
252 case 'r':
253 ch = '\r';
254 break;
255 case 't':
256 ch = '\t';
257 break;
258 case 'v':
259 ch = '\v';
260 break;
c906108c
SS
261 case 'x':
262 ch2 = fgetc (fp);
263 fputc (ch2, stdout);
264 fflush (stdout);
265 ch = tohex (ch2) << 4;
266 ch2 = fgetc (fp);
267 fputc (ch2, stdout);
268 fflush (stdout);
269 ch |= tohex (ch2);
270 break;
271 default:
272 /* Treat any other char as just itself */
273 break;
274 }
275 default:
276 break;
277 }
278 return (ch);
279}
280
281/* Accept input from gdb and match with chars from fp (after skipping one
282 blank) up until a \n is read from fp (which is not matched) */
283
82e0fd98 284static void
fba45db2 285expect (FILE *fp)
c906108c
SS
286{
287 int fromlog;
288 unsigned char fromgdb;
289
290 if ((fromlog = logchar (fp)) != ' ')
291 {
292 sync_error (fp, "Sync error during gdb read of leading blank", ' ',
293 fromlog);
294 }
295 do
296 {
297 fromlog = logchar (fp);
298 if (fromlog == EOL)
299 {
300 break;
301 }
302 read (remote_desc, &fromgdb, 1);
c5aa993b
JM
303 }
304 while (fromlog == fromgdb);
c906108c
SS
305 if (fromlog != EOL)
306 {
307 sync_error (fp, "Sync error during read of gdb packet", fromlog,
308 fromgdb);
309 }
310}
311
312/* Play data back to gdb from fp (after skipping leading blank) up until a
313 \n is read from fp (which is discarded and not sent to gdb). */
314
82e0fd98 315static void
fba45db2 316play (FILE *fp)
c906108c
SS
317{
318 int fromlog;
319 char ch;
320
321 if ((fromlog = logchar (fp)) != ' ')
322 {
323 sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
324 fromlog);
325 }
326 while ((fromlog = logchar (fp)) != EOL)
327 {
328 ch = fromlog;
329 write (remote_desc, &ch, 1);
330 }
331}
332
333int
da85418c 334main (int argc, char *argv[])
c906108c
SS
335{
336 FILE *fp;
337 int ch;
338
339 if (argc < 3)
340 {
341 fprintf (stderr, "Usage: gdbreplay <logfile> <host:port>\n");
342 fflush (stderr);
343 exit (1);
344 }
345 fp = fopen (argv[1], "r");
346 if (fp == NULL)
347 {
348 perror_with_name (argv[1]);
c5aa993b 349 }
c906108c
SS
350 remote_open (argv[2]);
351 while ((ch = logchar (fp)) != EOF)
352 {
353 switch (ch)
354 {
355 case 'w':
356 /* data sent from gdb to gdbreplay, accept and match it */
357 expect (fp);
358 break;
359 case 'r':
360 /* data sent from gdbreplay to gdb, play it */
361 play (fp);
362 break;
363 case 'c':
364 /* Command executed by gdb */
365 while ((ch = logchar (fp)) != EOL);
366 break;
367 }
368 }
369 remote_close ();
370 exit (0);
371}