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