2005-01-19 Andrew Cagney <cagney@gnu.org>
[deliverable/binutils-gdb.git] / gdb / gdbserver / gdbreplay.c
CommitLineData
c906108c 1/* Replay a remote debug session logfile for GDB.
6d782a97 2 Copyright 1996, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
c906108c
SS
3 Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.
4
c5aa993b 5 This file is part of GDB.
c906108c 6
c5aa993b
JM
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.
c906108c 11
c5aa993b
JM
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.
c906108c 16
c5aa993b
JM
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. */
c906108c 21
5c44784c 22#include "config.h"
c906108c
SS
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>
5c44784c 32#include <errno.h>
0729219d 33
82e0fd98
DB
34#ifdef HAVE_STDLIB_H
35#include <stdlib.h>
36#endif
0729219d
DJ
37#ifdef HAVE_STRING_H
38#include <string.h>
39#endif
82e0fd98
DB
40#ifdef HAVE_UNISTD_H
41#include <unistd.h>
42#endif
c906108c
SS
43
44/* Sort of a hack... */
45#define EOL (EOF - 1)
46
47static 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
82e0fd98 53static void
fba45db2 54perror_with_name (char *string)
c906108c 55{
5c44784c 56#ifndef STDC_HEADERS
c906108c 57 extern int errno;
5c44784c
JM
58#endif
59 const char *err;
c906108c
SS
60 char *combined;
61
43d5792c
DJ
62 err = strerror (errno);
63 if (err == NULL)
64 err = "unknown error";
65
c906108c
SS
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
75static void
fba45db2 76sync_error (FILE *fp, char *desc, int expect, int got)
c906108c
SS
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
82e0fd98 85static void
fba45db2 86remote_close (void)
c906108c
SS
87{
88 close (remote_desc);
89}
90
91/* Open a connection to a remote debugger.
92 NAME is the filename used for communication. */
93
82e0fd98 94static void
fba45db2 95remote_open (char *name)
c906108c 96{
c906108c
SS
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;
c906108c
SS
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;
c5aa993b
JM
121 setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
122 sizeof (tmp));
c906108c
SS
123
124 sockaddr.sin_family = PF_INET;
c5aa993b 125 sockaddr.sin_port = htons (port);
c906108c
SS
126 sockaddr.sin_addr.s_addr = INADDR_ANY;
127
c5aa993b 128 if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
c906108c
SS
129 || listen (tmp_desc, 1))
130 perror_with_name ("Can't bind address");
131
132 tmp = sizeof (sockaddr);
c5aa993b 133 remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
c906108c
SS
134 if (remote_desc == -1)
135 perror_with_name ("Accept failed");
136
c906108c
SS
137 /* Enable TCP keep alive process. */
138 tmp = 1;
c5aa993b 139 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
c906108c
SS
140
141 /* Tell TCP not to delay small packets. This greatly speeds up
c5aa993b 142 interactive response. */
c906108c 143 tmp = 1;
373fe97f 144 setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
c5aa993b 145 (char *) &tmp, sizeof (tmp));
c906108c
SS
146
147 close (tmp_desc); /* No longer need this */
148
c5aa993b
JM
149 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply
150 exits when the remote side dies. */
c906108c
SS
151 }
152
153 fcntl (remote_desc, F_SETFL, FASYNC);
154
155 fprintf (stderr, "Replay logfile using %s\n", name);
156 fflush (stderr);
157}
158
c5aa993b 159static int
fba45db2 160tohex (int ch)
c906108c
SS
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
179static int
fba45db2 180logchar (FILE *fp)
c906108c
SS
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 {
c5aa993b
JM
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;
c906108c
SS
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
82e0fd98 242static void
fba45db2 243expect (FILE *fp)
c906108c
SS
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);
c5aa993b
JM
261 }
262 while (fromlog == fromgdb);
c906108c
SS
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
82e0fd98 273static void
fba45db2 274play (FILE *fp)
c906108c
SS
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
291int
da85418c 292main (int argc, char *argv[])
c906108c
SS
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]);
c5aa993b 307 }
c906108c
SS
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.481336 seconds and 4 git commands to generate.