* configure.in (--without-headers): Add missing double quotes.
[deliverable/binutils-gdb.git] / gdb / gdbserver / gdbreplay.c
1 /* Replay a remote debug session logfile for GDB.
2 Copyright 1996, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
3 Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include "config.h"
23 #include <stdio.h>
24 #include <sys/file.h>
25 #include <netinet/in.h>
26 #include <sys/socket.h>
27 #include <netdb.h>
28 #include <netinet/tcp.h>
29 #include <signal.h>
30 #include <ctype.h>
31 #include <fcntl.h>
32 #include <errno.h>
33
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43
44 /* Sort of a hack... */
45 #define EOL (EOF - 1)
46
47 static int remote_desc;
48
49 /* Print the system error message for errno, and also mention STRING
50 as the file name for which the error was encountered.
51 Then return to command level. */
52
53 static void
54 perror_with_name (char *string)
55 {
56 #ifndef STDC_HEADERS
57 extern int errno;
58 #endif
59 const char *err;
60 char *combined;
61
62 err = strerror (errno);
63 if (err == NULL)
64 err = "unknown error";
65
66 combined = (char *) alloca (strlen (err) + strlen (string) + 3);
67 strcpy (combined, string);
68 strcat (combined, ": ");
69 strcat (combined, err);
70 fprintf (stderr, "\n%s.\n", combined);
71 fflush (stderr);
72 exit (1);
73 }
74
75 static void
76 sync_error (FILE *fp, char *desc, int expect, int got)
77 {
78 fprintf (stderr, "\n%s\n", desc);
79 fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
80 ftell (fp), expect, got);
81 fflush (stderr);
82 exit (1);
83 }
84
85 static void
86 remote_close (void)
87 {
88 close (remote_desc);
89 }
90
91 /* Open a connection to a remote debugger.
92 NAME is the filename used for communication. */
93
94 static void
95 remote_open (char *name)
96 {
97 if (!strchr (name, ':'))
98 {
99 fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
100 fflush (stderr);
101 exit (1);
102 }
103 else
104 {
105 char *port_str;
106 int port;
107 struct sockaddr_in sockaddr;
108 int tmp;
109 int tmp_desc;
110
111 port_str = strchr (name, ':');
112
113 port = atoi (port_str + 1);
114
115 tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
116 if (tmp_desc < 0)
117 perror_with_name ("Can't open socket");
118
119 /* Allow rapid reuse of this port. */
120 tmp = 1;
121 setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
122 sizeof (tmp));
123
124 sockaddr.sin_family = PF_INET;
125 sockaddr.sin_port = htons (port);
126 sockaddr.sin_addr.s_addr = INADDR_ANY;
127
128 if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
129 || listen (tmp_desc, 1))
130 perror_with_name ("Can't bind address");
131
132 tmp = sizeof (sockaddr);
133 remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
134 if (remote_desc == -1)
135 perror_with_name ("Accept failed");
136
137 /* Enable TCP keep alive process. */
138 tmp = 1;
139 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
140
141 /* Tell TCP not to delay small packets. This greatly speeds up
142 interactive response. */
143 tmp = 1;
144 setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
145 (char *) &tmp, sizeof (tmp));
146
147 close (tmp_desc); /* No longer need this */
148
149 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply
150 exits when the remote side dies. */
151 }
152
153 fcntl (remote_desc, F_SETFL, FASYNC);
154
155 fprintf (stderr, "Replay logfile using %s\n", name);
156 fflush (stderr);
157 }
158
159 static int
160 tohex (int ch)
161 {
162 if (ch >= '0' && ch <= '9')
163 {
164 return (ch - '0');
165 }
166 if (ch >= 'A' && ch <= 'F')
167 {
168 return (ch - 'A' + 10);
169 }
170 if (ch >= 'a' && ch <= 'f')
171 {
172 return (ch - 'a' + 10);
173 }
174 fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
175 fflush (stderr);
176 exit (1);
177 }
178
179 static int
180 logchar (FILE *fp)
181 {
182 int ch;
183 int ch2;
184
185 ch = fgetc (fp);
186 fputc (ch, stdout);
187 fflush (stdout);
188 switch (ch)
189 {
190 case '\n':
191 ch = EOL;
192 break;
193 case '\\':
194 ch = fgetc (fp);
195 fputc (ch, stdout);
196 fflush (stdout);
197 switch (ch)
198 {
199 case '\\':
200 break;
201 case 'b':
202 ch = '\b';
203 break;
204 case 'f':
205 ch = '\f';
206 break;
207 case 'n':
208 ch = '\n';
209 break;
210 case 'r':
211 ch = '\r';
212 break;
213 case 't':
214 ch = '\t';
215 break;
216 case 'v':
217 ch = '\v';
218 break;
219 case 'x':
220 ch2 = fgetc (fp);
221 fputc (ch2, stdout);
222 fflush (stdout);
223 ch = tohex (ch2) << 4;
224 ch2 = fgetc (fp);
225 fputc (ch2, stdout);
226 fflush (stdout);
227 ch |= tohex (ch2);
228 break;
229 default:
230 /* Treat any other char as just itself */
231 break;
232 }
233 default:
234 break;
235 }
236 return (ch);
237 }
238
239 /* Accept input from gdb and match with chars from fp (after skipping one
240 blank) up until a \n is read from fp (which is not matched) */
241
242 static void
243 expect (FILE *fp)
244 {
245 int fromlog;
246 unsigned char fromgdb;
247
248 if ((fromlog = logchar (fp)) != ' ')
249 {
250 sync_error (fp, "Sync error during gdb read of leading blank", ' ',
251 fromlog);
252 }
253 do
254 {
255 fromlog = logchar (fp);
256 if (fromlog == EOL)
257 {
258 break;
259 }
260 read (remote_desc, &fromgdb, 1);
261 }
262 while (fromlog == fromgdb);
263 if (fromlog != EOL)
264 {
265 sync_error (fp, "Sync error during read of gdb packet", fromlog,
266 fromgdb);
267 }
268 }
269
270 /* Play data back to gdb from fp (after skipping leading blank) up until a
271 \n is read from fp (which is discarded and not sent to gdb). */
272
273 static void
274 play (FILE *fp)
275 {
276 int fromlog;
277 char ch;
278
279 if ((fromlog = logchar (fp)) != ' ')
280 {
281 sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
282 fromlog);
283 }
284 while ((fromlog = logchar (fp)) != EOL)
285 {
286 ch = fromlog;
287 write (remote_desc, &ch, 1);
288 }
289 }
290
291 int
292 main (int argc, char *argv[])
293 {
294 FILE *fp;
295 int ch;
296
297 if (argc < 3)
298 {
299 fprintf (stderr, "Usage: gdbreplay <logfile> <host:port>\n");
300 fflush (stderr);
301 exit (1);
302 }
303 fp = fopen (argv[1], "r");
304 if (fp == NULL)
305 {
306 perror_with_name (argv[1]);
307 }
308 remote_open (argv[2]);
309 while ((ch = logchar (fp)) != EOF)
310 {
311 switch (ch)
312 {
313 case 'w':
314 /* data sent from gdb to gdbreplay, accept and match it */
315 expect (fp);
316 break;
317 case 'r':
318 /* data sent from gdbreplay to gdb, play it */
319 play (fp);
320 break;
321 case 'c':
322 /* Command executed by gdb */
323 while ((ch = logchar (fp)) != EOL);
324 break;
325 }
326 }
327 remote_close ();
328 exit (0);
329 }
This page took 0.037127 seconds and 4 git commands to generate.