Sigh, should have updated the copyright date in the
[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;
c906108c
SS
100 int tmp_desc;
101
102 port_str = strchr (name, ':');
103
104 port = atoi (port_str + 1);
105
106 tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
107 if (tmp_desc < 0)
108 perror_with_name ("Can't open socket");
109
110 /* Allow rapid reuse of this port. */
111 tmp = 1;
c5aa993b
JM
112 setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
113 sizeof (tmp));
c906108c
SS
114
115 sockaddr.sin_family = PF_INET;
c5aa993b 116 sockaddr.sin_port = htons (port);
c906108c
SS
117 sockaddr.sin_addr.s_addr = INADDR_ANY;
118
c5aa993b 119 if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
c906108c
SS
120 || listen (tmp_desc, 1))
121 perror_with_name ("Can't bind address");
122
123 tmp = sizeof (sockaddr);
c5aa993b 124 remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
c906108c
SS
125 if (remote_desc == -1)
126 perror_with_name ("Accept failed");
127
c906108c
SS
128 /* Enable TCP keep alive process. */
129 tmp = 1;
c5aa993b 130 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
c906108c
SS
131
132 /* Tell TCP not to delay small packets. This greatly speeds up
c5aa993b 133 interactive response. */
c906108c 134 tmp = 1;
373fe97f 135 setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
c5aa993b 136 (char *) &tmp, sizeof (tmp));
c906108c
SS
137
138 close (tmp_desc); /* No longer need this */
139
c5aa993b
JM
140 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply
141 exits when the remote side dies. */
c906108c
SS
142 }
143
144 fcntl (remote_desc, F_SETFL, FASYNC);
145
146 fprintf (stderr, "Replay logfile using %s\n", name);
147 fflush (stderr);
148}
149
c5aa993b 150static int
fba45db2 151tohex (int ch)
c906108c
SS
152{
153 if (ch >= '0' && ch <= '9')
154 {
155 return (ch - '0');
156 }
157 if (ch >= 'A' && ch <= 'F')
158 {
159 return (ch - 'A' + 10);
160 }
161 if (ch >= 'a' && ch <= 'f')
162 {
163 return (ch - 'a' + 10);
164 }
165 fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
166 fflush (stderr);
167 exit (1);
168}
169
170static int
fba45db2 171logchar (FILE *fp)
c906108c
SS
172{
173 int ch;
174 int ch2;
175
176 ch = fgetc (fp);
177 fputc (ch, stdout);
178 fflush (stdout);
179 switch (ch)
180 {
181 case '\n':
182 ch = EOL;
183 break;
184 case '\\':
185 ch = fgetc (fp);
186 fputc (ch, stdout);
187 fflush (stdout);
188 switch (ch)
189 {
c5aa993b
JM
190 case '\\':
191 break;
192 case 'b':
193 ch = '\b';
194 break;
195 case 'f':
196 ch = '\f';
197 break;
198 case 'n':
199 ch = '\n';
200 break;
201 case 'r':
202 ch = '\r';
203 break;
204 case 't':
205 ch = '\t';
206 break;
207 case 'v':
208 ch = '\v';
209 break;
c906108c
SS
210 case 'x':
211 ch2 = fgetc (fp);
212 fputc (ch2, stdout);
213 fflush (stdout);
214 ch = tohex (ch2) << 4;
215 ch2 = fgetc (fp);
216 fputc (ch2, stdout);
217 fflush (stdout);
218 ch |= tohex (ch2);
219 break;
220 default:
221 /* Treat any other char as just itself */
222 break;
223 }
224 default:
225 break;
226 }
227 return (ch);
228}
229
230/* Accept input from gdb and match with chars from fp (after skipping one
231 blank) up until a \n is read from fp (which is not matched) */
232
233void
fba45db2 234expect (FILE *fp)
c906108c
SS
235{
236 int fromlog;
237 unsigned char fromgdb;
238
239 if ((fromlog = logchar (fp)) != ' ')
240 {
241 sync_error (fp, "Sync error during gdb read of leading blank", ' ',
242 fromlog);
243 }
244 do
245 {
246 fromlog = logchar (fp);
247 if (fromlog == EOL)
248 {
249 break;
250 }
251 read (remote_desc, &fromgdb, 1);
c5aa993b
JM
252 }
253 while (fromlog == fromgdb);
c906108c
SS
254 if (fromlog != EOL)
255 {
256 sync_error (fp, "Sync error during read of gdb packet", fromlog,
257 fromgdb);
258 }
259}
260
261/* Play data back to gdb from fp (after skipping leading blank) up until a
262 \n is read from fp (which is discarded and not sent to gdb). */
263
264void
fba45db2 265play (FILE *fp)
c906108c
SS
266{
267 int fromlog;
268 char ch;
269
270 if ((fromlog = logchar (fp)) != ' ')
271 {
272 sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
273 fromlog);
274 }
275 while ((fromlog = logchar (fp)) != EOL)
276 {
277 ch = fromlog;
278 write (remote_desc, &ch, 1);
279 }
280}
281
282int
da85418c 283main (int argc, char *argv[])
c906108c
SS
284{
285 FILE *fp;
286 int ch;
287
288 if (argc < 3)
289 {
290 fprintf (stderr, "Usage: gdbreplay <logfile> <host:port>\n");
291 fflush (stderr);
292 exit (1);
293 }
294 fp = fopen (argv[1], "r");
295 if (fp == NULL)
296 {
297 perror_with_name (argv[1]);
c5aa993b 298 }
c906108c
SS
299 remote_open (argv[2]);
300 while ((ch = logchar (fp)) != EOF)
301 {
302 switch (ch)
303 {
304 case 'w':
305 /* data sent from gdb to gdbreplay, accept and match it */
306 expect (fp);
307 break;
308 case 'r':
309 /* data sent from gdbreplay to gdb, play it */
310 play (fp);
311 break;
312 case 'c':
313 /* Command executed by gdb */
314 while ((ch = logchar (fp)) != EOL);
315 break;
316 }
317 }
318 remote_close ();
319 exit (0);
320}
This page took 0.164422 seconds and 4 git commands to generate.