-Wwrite-strings: The Rest
[deliverable/binutils-gdb.git] / gdb / gdbserver / gdbreplay.c
CommitLineData
c906108c 1/* Replay a remote debug session logfile for GDB.
61baf725 2 Copyright (C) 1996-2017 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
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
c5aa993b 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 17 You should have received a copy of the GNU General Public License
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c 19
5c44784c 20#include "config.h"
406b1477 21#include "build-gnulib-gdbserver/config.h"
01208463 22#include "version.h"
406b1477 23
c906108c 24#include <stdio.h>
68070c10 25#if HAVE_SYS_FILE_H
c906108c 26#include <sys/file.h>
68070c10
PA
27#endif
28#if HAVE_SIGNAL_H
c906108c 29#include <signal.h>
68070c10 30#endif
c906108c 31#include <ctype.h>
68070c10 32#if HAVE_FCNTL_H
c906108c 33#include <fcntl.h>
68070c10 34#endif
5c44784c 35#include <errno.h>
82e0fd98 36#include <stdlib.h>
0729219d 37#include <string.h>
82e0fd98 38#include <unistd.h>
9eb1356e
PA
39#ifdef HAVE_NETINET_IN_H
40#include <netinet/in.h>
41#endif
42#ifdef HAVE_SYS_SOCKET_H
43#include <sys/socket.h>
44#endif
b80864fb
DJ
45#if HAVE_NETDB_H
46#include <netdb.h>
47#endif
48#if HAVE_NETINET_TCP_H
49#include <netinet/tcp.h>
50#endif
9c232dda 51
a778ab81 52#include <alloca.h>
9c232dda 53
9eb1356e
PA
54#if USE_WIN32API
55#include <winsock2.h>
56#endif
c906108c 57
f450004a
DJ
58#ifndef HAVE_SOCKLEN_T
59typedef int socklen_t;
60#endif
61
c906108c
SS
62/* Sort of a hack... */
63#define EOL (EOF - 1)
64
65static int remote_desc;
66
68070c10
PA
67#ifdef __MINGW32CE__
68
69#ifndef COUNTOF
70#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0]))
71#endif
72
73#define errno (GetLastError ())
74
75char *
76strerror (DWORD error)
77{
78 static char buf[1024];
79 WCHAR *msgbuf;
80 DWORD lasterr = GetLastError ();
81 DWORD chars = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM
82 | FORMAT_MESSAGE_ALLOCATE_BUFFER,
83 NULL,
84 error,
85 0, /* Default language */
86 (LPVOID)&msgbuf,
87 0,
88 NULL);
89 if (chars != 0)
90 {
91 /* If there is an \r\n appended, zap it. */
92 if (chars >= 2
93 && msgbuf[chars - 2] == '\r'
94 && msgbuf[chars - 1] == '\n')
95 {
96 chars -= 2;
97 msgbuf[chars] = 0;
98 }
99
100 if (chars > ((COUNTOF (buf)) - 1))
101 {
102 chars = COUNTOF (buf) - 1;
103 msgbuf [chars] = 0;
104 }
105
106 wcstombs (buf, msgbuf, chars + 1);
107 LocalFree (msgbuf);
108 }
109 else
110 sprintf (buf, "unknown win32 error (%ld)", error);
111
112 SetLastError (lasterr);
113 return buf;
114}
115
116#endif /* __MINGW32CE__ */
117
c906108c
SS
118/* Print the system error message for errno, and also mention STRING
119 as the file name for which the error was encountered.
120 Then return to command level. */
121
82e0fd98 122static void
54363045 123perror_with_name (const char *string)
c906108c 124{
5c44784c 125#ifndef STDC_HEADERS
c906108c 126 extern int errno;
5c44784c
JM
127#endif
128 const char *err;
c906108c
SS
129 char *combined;
130
43d5792c
DJ
131 err = strerror (errno);
132 if (err == NULL)
133 err = "unknown error";
134
c906108c
SS
135 combined = (char *) alloca (strlen (err) + strlen (string) + 3);
136 strcpy (combined, string);
137 strcat (combined, ": ");
138 strcat (combined, err);
139 fprintf (stderr, "\n%s.\n", combined);
140 fflush (stderr);
141 exit (1);
142}
143
144static void
a121b7c1 145sync_error (FILE *fp, const char *desc, int expect, int got)
c906108c
SS
146{
147 fprintf (stderr, "\n%s\n", desc);
148 fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
149 ftell (fp), expect, got);
150 fflush (stderr);
151 exit (1);
152}
153
e581f2b4
PA
154static void
155remote_error (const char *desc)
156{
157 fprintf (stderr, "\n%s\n", desc);
158 fflush (stderr);
159 exit (1);
160}
161
82e0fd98 162static void
fba45db2 163remote_close (void)
c906108c 164{
b80864fb
DJ
165#ifdef USE_WIN32API
166 closesocket (remote_desc);
167#else
c906108c 168 close (remote_desc);
b80864fb 169#endif
c906108c
SS
170}
171
172/* Open a connection to a remote debugger.
173 NAME is the filename used for communication. */
174
82e0fd98 175static void
fba45db2 176remote_open (char *name)
c906108c 177{
c906108c
SS
178 if (!strchr (name, ':'))
179 {
180 fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
181 fflush (stderr);
182 exit (1);
183 }
184 else
185 {
b80864fb
DJ
186#ifdef USE_WIN32API
187 static int winsock_initialized;
188#endif
c906108c
SS
189 char *port_str;
190 int port;
9eb1356e 191 struct sockaddr_in sockaddr;
f450004a 192 socklen_t tmp;
c906108c
SS
193 int tmp_desc;
194
195 port_str = strchr (name, ':');
196
197 port = atoi (port_str + 1);
198
b80864fb
DJ
199#ifdef USE_WIN32API
200 if (!winsock_initialized)
201 {
202 WSADATA wsad;
203
204 WSAStartup (MAKEWORD (1, 0), &wsad);
205 winsock_initialized = 1;
206 }
207#endif
208
c906108c 209 tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
363a6e9f 210 if (tmp_desc == -1)
c906108c
SS
211 perror_with_name ("Can't open socket");
212
213 /* Allow rapid reuse of this port. */
214 tmp = 1;
c5aa993b
JM
215 setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
216 sizeof (tmp));
c906108c 217
9eb1356e
PA
218 sockaddr.sin_family = PF_INET;
219 sockaddr.sin_port = htons (port);
220 sockaddr.sin_addr.s_addr = INADDR_ANY;
c906108c 221
9eb1356e 222 if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
c906108c
SS
223 || listen (tmp_desc, 1))
224 perror_with_name ("Can't bind address");
225
9eb1356e
PA
226 tmp = sizeof (sockaddr);
227 remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
c906108c
SS
228 if (remote_desc == -1)
229 perror_with_name ("Accept failed");
230
c906108c
SS
231 /* Enable TCP keep alive process. */
232 tmp = 1;
493e2a69
MS
233 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE,
234 (char *) &tmp, sizeof (tmp));
c906108c
SS
235
236 /* Tell TCP not to delay small packets. This greatly speeds up
1b3f6016 237 interactive response. */
c906108c 238 tmp = 1;
373fe97f 239 setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
c5aa993b 240 (char *) &tmp, sizeof (tmp));
c906108c 241
b80864fb
DJ
242#ifndef USE_WIN32API
243 close (tmp_desc); /* No longer need this */
244
493e2a69
MS
245 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then
246 gdbreplay simply exits when
247 the remote side dies. */
b80864fb
DJ
248#else
249 closesocket (tmp_desc); /* No longer need this */
250#endif
c906108c
SS
251 }
252
b80864fb 253#if defined(F_SETFL) && defined (FASYNC)
c906108c 254 fcntl (remote_desc, F_SETFL, FASYNC);
b80864fb 255#endif
c906108c
SS
256
257 fprintf (stderr, "Replay logfile using %s\n", name);
258 fflush (stderr);
259}
260
c5aa993b 261static int
909c2cda 262fromhex (int ch)
c906108c
SS
263{
264 if (ch >= '0' && ch <= '9')
265 {
266 return (ch - '0');
267 }
268 if (ch >= 'A' && ch <= 'F')
269 {
270 return (ch - 'A' + 10);
271 }
272 if (ch >= 'a' && ch <= 'f')
273 {
274 return (ch - 'a' + 10);
275 }
276 fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
277 fflush (stderr);
278 exit (1);
279}
280
281static int
fba45db2 282logchar (FILE *fp)
c906108c
SS
283{
284 int ch;
285 int ch2;
286
287 ch = fgetc (fp);
288 fputc (ch, stdout);
289 fflush (stdout);
290 switch (ch)
291 {
292 case '\n':
293 ch = EOL;
294 break;
295 case '\\':
296 ch = fgetc (fp);
297 fputc (ch, stdout);
298 fflush (stdout);
299 switch (ch)
300 {
c5aa993b
JM
301 case '\\':
302 break;
303 case 'b':
304 ch = '\b';
305 break;
306 case 'f':
307 ch = '\f';
308 break;
309 case 'n':
310 ch = '\n';
311 break;
312 case 'r':
313 ch = '\r';
314 break;
315 case 't':
316 ch = '\t';
317 break;
318 case 'v':
319 ch = '\v';
320 break;
c906108c
SS
321 case 'x':
322 ch2 = fgetc (fp);
323 fputc (ch2, stdout);
324 fflush (stdout);
909c2cda 325 ch = fromhex (ch2) << 4;
c906108c
SS
326 ch2 = fgetc (fp);
327 fputc (ch2, stdout);
328 fflush (stdout);
909c2cda 329 ch |= fromhex (ch2);
c906108c
SS
330 break;
331 default:
332 /* Treat any other char as just itself */
333 break;
334 }
335 default:
336 break;
337 }
338 return (ch);
339}
340
e581f2b4
PA
341static int
342gdbchar (int desc)
343{
344 unsigned char fromgdb;
345
346 if (read (desc, &fromgdb, 1) != 1)
347 return -1;
348 else
349 return fromgdb;
350}
351
c906108c
SS
352/* Accept input from gdb and match with chars from fp (after skipping one
353 blank) up until a \n is read from fp (which is not matched) */
354
82e0fd98 355static void
fba45db2 356expect (FILE *fp)
c906108c
SS
357{
358 int fromlog;
e581f2b4 359 int fromgdb;
c906108c
SS
360
361 if ((fromlog = logchar (fp)) != ' ')
362 {
363 sync_error (fp, "Sync error during gdb read of leading blank", ' ',
364 fromlog);
365 }
366 do
367 {
368 fromlog = logchar (fp);
369 if (fromlog == EOL)
e581f2b4
PA
370 break;
371 fromgdb = gdbchar (remote_desc);
372 if (fromgdb < 0)
373 remote_error ("Error during read from gdb");
c5aa993b
JM
374 }
375 while (fromlog == fromgdb);
e581f2b4 376
c906108c
SS
377 if (fromlog != EOL)
378 {
e581f2b4 379 sync_error (fp, "Sync error during read of gdb packet from log", fromlog,
c906108c
SS
380 fromgdb);
381 }
382}
383
384/* Play data back to gdb from fp (after skipping leading blank) up until a
385 \n is read from fp (which is discarded and not sent to gdb). */
386
82e0fd98 387static void
fba45db2 388play (FILE *fp)
c906108c
SS
389{
390 int fromlog;
391 char ch;
392
393 if ((fromlog = logchar (fp)) != ' ')
394 {
395 sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
396 fromlog);
397 }
398 while ((fromlog = logchar (fp)) != EOL)
399 {
400 ch = fromlog;
e581f2b4
PA
401 if (write (remote_desc, &ch, 1) != 1)
402 remote_error ("Error during write to gdb");
c906108c
SS
403 }
404}
405
c16158bc
JM
406static void
407gdbreplay_version (void)
408{
409 printf ("GNU gdbreplay %s%s\n"
61baf725 410 "Copyright (C) 2017 Free Software Foundation, Inc.\n"
493e2a69
MS
411 "gdbreplay is free software, covered by "
412 "the GNU General Public License.\n"
90aa6a40 413 "This gdbreplay was configured as \"%s\"\n",
c16158bc
JM
414 PKGVERSION, version, host_name);
415}
416
417static void
418gdbreplay_usage (FILE *stream)
419{
420 fprintf (stream, "Usage:\tgdbreplay <logfile> <host:port>\n");
421 if (REPORT_BUGS_TO[0] && stream == stdout)
422 fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO);
423}
424
c906108c 425int
da85418c 426main (int argc, char *argv[])
c906108c
SS
427{
428 FILE *fp;
429 int ch;
430
c16158bc
JM
431 if (argc >= 2 && strcmp (argv[1], "--version") == 0)
432 {
433 gdbreplay_version ();
434 exit (0);
435 }
436 if (argc >= 2 && strcmp (argv[1], "--help") == 0)
437 {
438 gdbreplay_usage (stdout);
439 exit (0);
440 }
441
c906108c
SS
442 if (argc < 3)
443 {
c16158bc 444 gdbreplay_usage (stderr);
c906108c
SS
445 exit (1);
446 }
447 fp = fopen (argv[1], "r");
448 if (fp == NULL)
449 {
450 perror_with_name (argv[1]);
c5aa993b 451 }
c906108c
SS
452 remote_open (argv[2]);
453 while ((ch = logchar (fp)) != EOF)
454 {
455 switch (ch)
456 {
457 case 'w':
458 /* data sent from gdb to gdbreplay, accept and match it */
459 expect (fp);
460 break;
461 case 'r':
462 /* data sent from gdbreplay to gdb, play it */
463 play (fp);
464 break;
465 case 'c':
466 /* Command executed by gdb */
467 while ((ch = logchar (fp)) != EOL);
468 break;
469 }
470 }
471 remote_close ();
472 exit (0);
473}
This page took 1.188073 seconds and 4 git commands to generate.