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