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