]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/gdbserver/gdbreplay.c
* acconfig.h: Remove.
[thirdparty/binutils-gdb.git] / gdb / gdbserver / gdbreplay.c
CommitLineData
c906108c 1/* Replay a remote debug session logfile for GDB.
f450004a
DJ
2 Copyright 1996, 1998, 1999, 2000, 2002, 2003, 2005
3 Free Software Foundation, Inc.
c906108c
SS
4 Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.
5
c5aa993b 6 This file is part of GDB.
c906108c 7
c5aa993b
JM
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
c906108c 12
c5aa993b
JM
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
c906108c 17
c5aa993b
JM
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
c906108c 22
5c44784c 23#include "config.h"
c906108c
SS
24#include <stdio.h>
25#include <sys/file.h>
26#include <netinet/in.h>
27#include <sys/socket.h>
28#include <netdb.h>
29#include <netinet/tcp.h>
30#include <signal.h>
31#include <ctype.h>
32#include <fcntl.h>
5c44784c 33#include <errno.h>
0729219d 34
82e0fd98
DB
35#ifdef HAVE_STDLIB_H
36#include <stdlib.h>
37#endif
0729219d
DJ
38#ifdef HAVE_STRING_H
39#include <string.h>
40#endif
82e0fd98
DB
41#ifdef HAVE_UNISTD_H
42#include <unistd.h>
43#endif
c906108c 44
f450004a
DJ
45#ifndef HAVE_SOCKLEN_T
46typedef int socklen_t;
47#endif
48
c906108c
SS
49/* Sort of a hack... */
50#define EOL (EOF - 1)
51
52static int remote_desc;
53
54/* Print the system error message for errno, and also mention STRING
55 as the file name for which the error was encountered.
56 Then return to command level. */
57
82e0fd98 58static void
fba45db2 59perror_with_name (char *string)
c906108c 60{
5c44784c 61#ifndef STDC_HEADERS
c906108c 62 extern int errno;
5c44784c
JM
63#endif
64 const char *err;
c906108c
SS
65 char *combined;
66
43d5792c
DJ
67 err = strerror (errno);
68 if (err == NULL)
69 err = "unknown error";
70
c906108c
SS
71 combined = (char *) alloca (strlen (err) + strlen (string) + 3);
72 strcpy (combined, string);
73 strcat (combined, ": ");
74 strcat (combined, err);
75 fprintf (stderr, "\n%s.\n", combined);
76 fflush (stderr);
77 exit (1);
78}
79
80static void
fba45db2 81sync_error (FILE *fp, char *desc, int expect, int got)
c906108c
SS
82{
83 fprintf (stderr, "\n%s\n", desc);
84 fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
85 ftell (fp), expect, got);
86 fflush (stderr);
87 exit (1);
88}
89
82e0fd98 90static void
fba45db2 91remote_close (void)
c906108c
SS
92{
93 close (remote_desc);
94}
95
96/* Open a connection to a remote debugger.
97 NAME is the filename used for communication. */
98
82e0fd98 99static void
fba45db2 100remote_open (char *name)
c906108c 101{
c906108c
SS
102 if (!strchr (name, ':'))
103 {
104 fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
105 fflush (stderr);
106 exit (1);
107 }
108 else
109 {
110 char *port_str;
111 int port;
112 struct sockaddr_in sockaddr;
f450004a 113 socklen_t tmp;
c906108c
SS
114 int tmp_desc;
115
116 port_str = strchr (name, ':');
117
118 port = atoi (port_str + 1);
119
120 tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
121 if (tmp_desc < 0)
122 perror_with_name ("Can't open socket");
123
124 /* Allow rapid reuse of this port. */
125 tmp = 1;
c5aa993b
JM
126 setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
127 sizeof (tmp));
c906108c
SS
128
129 sockaddr.sin_family = PF_INET;
c5aa993b 130 sockaddr.sin_port = htons (port);
c906108c
SS
131 sockaddr.sin_addr.s_addr = INADDR_ANY;
132
c5aa993b 133 if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
c906108c
SS
134 || listen (tmp_desc, 1))
135 perror_with_name ("Can't bind address");
136
137 tmp = sizeof (sockaddr);
c5aa993b 138 remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
c906108c
SS
139 if (remote_desc == -1)
140 perror_with_name ("Accept failed");
141
c906108c
SS
142 /* Enable TCP keep alive process. */
143 tmp = 1;
c5aa993b 144 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
c906108c
SS
145
146 /* Tell TCP not to delay small packets. This greatly speeds up
c5aa993b 147 interactive response. */
c906108c 148 tmp = 1;
373fe97f 149 setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
c5aa993b 150 (char *) &tmp, sizeof (tmp));
c906108c
SS
151
152 close (tmp_desc); /* No longer need this */
153
c5aa993b
JM
154 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbreplay simply
155 exits when the remote side dies. */
c906108c
SS
156 }
157
158 fcntl (remote_desc, F_SETFL, FASYNC);
159
160 fprintf (stderr, "Replay logfile using %s\n", name);
161 fflush (stderr);
162}
163
c5aa993b 164static int
fba45db2 165tohex (int ch)
c906108c
SS
166{
167 if (ch >= '0' && ch <= '9')
168 {
169 return (ch - '0');
170 }
171 if (ch >= 'A' && ch <= 'F')
172 {
173 return (ch - 'A' + 10);
174 }
175 if (ch >= 'a' && ch <= 'f')
176 {
177 return (ch - 'a' + 10);
178 }
179 fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
180 fflush (stderr);
181 exit (1);
182}
183
184static int
fba45db2 185logchar (FILE *fp)
c906108c
SS
186{
187 int ch;
188 int ch2;
189
190 ch = fgetc (fp);
191 fputc (ch, stdout);
192 fflush (stdout);
193 switch (ch)
194 {
195 case '\n':
196 ch = EOL;
197 break;
198 case '\\':
199 ch = fgetc (fp);
200 fputc (ch, stdout);
201 fflush (stdout);
202 switch (ch)
203 {
c5aa993b
JM
204 case '\\':
205 break;
206 case 'b':
207 ch = '\b';
208 break;
209 case 'f':
210 ch = '\f';
211 break;
212 case 'n':
213 ch = '\n';
214 break;
215 case 'r':
216 ch = '\r';
217 break;
218 case 't':
219 ch = '\t';
220 break;
221 case 'v':
222 ch = '\v';
223 break;
c906108c
SS
224 case 'x':
225 ch2 = fgetc (fp);
226 fputc (ch2, stdout);
227 fflush (stdout);
228 ch = tohex (ch2) << 4;
229 ch2 = fgetc (fp);
230 fputc (ch2, stdout);
231 fflush (stdout);
232 ch |= tohex (ch2);
233 break;
234 default:
235 /* Treat any other char as just itself */
236 break;
237 }
238 default:
239 break;
240 }
241 return (ch);
242}
243
244/* Accept input from gdb and match with chars from fp (after skipping one
245 blank) up until a \n is read from fp (which is not matched) */
246
82e0fd98 247static void
fba45db2 248expect (FILE *fp)
c906108c
SS
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
82e0fd98 278static void
fba45db2 279play (FILE *fp)
c906108c
SS
280{
281 int fromlog;
282 char ch;
283
284 if ((fromlog = logchar (fp)) != ' ')
285 {
286 sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
287 fromlog);
288 }
289 while ((fromlog = logchar (fp)) != EOL)
290 {
291 ch = fromlog;
292 write (remote_desc, &ch, 1);
293 }
294}
295
296int
da85418c 297main (int argc, char *argv[])
c906108c
SS
298{
299 FILE *fp;
300 int ch;
301
302 if (argc < 3)
303 {
304 fprintf (stderr, "Usage: gdbreplay <logfile> <host:port>\n");
305 fflush (stderr);
306 exit (1);
307 }
308 fp = fopen (argv[1], "r");
309 if (fp == NULL)
310 {
311 perror_with_name (argv[1]);
c5aa993b 312 }
c906108c
SS
313 remote_open (argv[2]);
314 while ((ch = logchar (fp)) != EOF)
315 {
316 switch (ch)
317 {
318 case 'w':
319 /* data sent from gdb to gdbreplay, accept and match it */
320 expect (fp);
321 break;
322 case 'r':
323 /* data sent from gdbreplay to gdb, play it */
324 play (fp);
325 break;
326 case 'c':
327 /* Command executed by gdb */
328 while ((ch = logchar (fp)) != EOL);
329 break;
330 }
331 }
332 remote_close ();
333 exit (0);
334}