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