Handle \r\n in gdbreplay
[deliverable/binutils-gdb.git] / gdb / gdbserver / gdbreplay.c
CommitLineData
c906108c 1/* Replay a remote debug session logfile for GDB.
42a4f53d 2 Copyright (C) 1996-2019 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
0747795c
TT
20#include "common/common-defs.h"
21#include "common/version.h"
406b1477 22
68070c10 23#if HAVE_SYS_FILE_H
c906108c 24#include <sys/file.h>
68070c10
PA
25#endif
26#if HAVE_SIGNAL_H
c906108c 27#include <signal.h>
68070c10 28#endif
c906108c 29#include <ctype.h>
68070c10 30#if HAVE_FCNTL_H
c906108c 31#include <fcntl.h>
68070c10 32#endif
82e0fd98 33#include <unistd.h>
9eb1356e
PA
34#ifdef HAVE_NETINET_IN_H
35#include <netinet/in.h>
36#endif
37#ifdef HAVE_SYS_SOCKET_H
38#include <sys/socket.h>
39#endif
b80864fb
DJ
40#if HAVE_NETDB_H
41#include <netdb.h>
42#endif
43#if HAVE_NETINET_TCP_H
44#include <netinet/tcp.h>
45#endif
9c232dda 46
9eb1356e
PA
47#if USE_WIN32API
48#include <winsock2.h>
c7ab0aef 49#include <wspiapi.h>
9eb1356e 50#endif
c906108c 51
0747795c 52#include "common/netstuff.h"
c7ab0aef 53
f450004a
DJ
54#ifndef HAVE_SOCKLEN_T
55typedef int socklen_t;
56#endif
57
c906108c
SS
58/* Sort of a hack... */
59#define EOL (EOF - 1)
60
61static int remote_desc;
62
68070c10
PA
63#ifdef __MINGW32CE__
64
65#ifndef COUNTOF
66#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0]))
67#endif
68
69#define errno (GetLastError ())
70
71char *
72strerror (DWORD error)
73{
74 static char buf[1024];
75 WCHAR *msgbuf;
76 DWORD lasterr = GetLastError ();
77 DWORD chars = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM
78 | FORMAT_MESSAGE_ALLOCATE_BUFFER,
79 NULL,
80 error,
81 0, /* Default language */
82 (LPVOID)&msgbuf,
83 0,
84 NULL);
85 if (chars != 0)
86 {
87 /* If there is an \r\n appended, zap it. */
88 if (chars >= 2
89 && msgbuf[chars - 2] == '\r'
90 && msgbuf[chars - 1] == '\n')
91 {
92 chars -= 2;
93 msgbuf[chars] = 0;
94 }
95
96 if (chars > ((COUNTOF (buf)) - 1))
97 {
98 chars = COUNTOF (buf) - 1;
99 msgbuf [chars] = 0;
100 }
101
102 wcstombs (buf, msgbuf, chars + 1);
103 LocalFree (msgbuf);
104 }
105 else
106 sprintf (buf, "unknown win32 error (%ld)", error);
107
108 SetLastError (lasterr);
109 return buf;
110}
111
112#endif /* __MINGW32CE__ */
113
c906108c 114static void
a121b7c1 115sync_error (FILE *fp, const char *desc, int expect, int got)
c906108c
SS
116{
117 fprintf (stderr, "\n%s\n", desc);
118 fprintf (stderr, "At logfile offset %ld, expected '0x%x' got '0x%x'\n",
119 ftell (fp), expect, got);
120 fflush (stderr);
121 exit (1);
122}
123
e581f2b4
PA
124static void
125remote_error (const char *desc)
126{
127 fprintf (stderr, "\n%s\n", desc);
128 fflush (stderr);
129 exit (1);
130}
131
82e0fd98 132static void
fba45db2 133remote_close (void)
c906108c 134{
b80864fb
DJ
135#ifdef USE_WIN32API
136 closesocket (remote_desc);
137#else
c906108c 138 close (remote_desc);
b80864fb 139#endif
c906108c
SS
140}
141
142/* Open a connection to a remote debugger.
143 NAME is the filename used for communication. */
144
82e0fd98 145static void
fba45db2 146remote_open (char *name)
c906108c 147{
c7ab0aef
SDJ
148 char *last_colon = strrchr (name, ':');
149
150 if (last_colon == NULL)
c906108c
SS
151 {
152 fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
153 fflush (stderr);
154 exit (1);
155 }
c7ab0aef 156
b80864fb 157#ifdef USE_WIN32API
c7ab0aef 158 static int winsock_initialized;
b80864fb 159#endif
c7ab0aef
SDJ
160 int tmp;
161 int tmp_desc;
162 struct addrinfo hint;
163 struct addrinfo *ainfo;
c906108c 164
c7ab0aef
SDJ
165 memset (&hint, 0, sizeof (hint));
166 /* Assume no prefix will be passed, therefore we should use
167 AF_UNSPEC. */
168 hint.ai_family = AF_UNSPEC;
169 hint.ai_socktype = SOCK_STREAM;
170 hint.ai_protocol = IPPROTO_TCP;
c906108c 171
c7ab0aef
SDJ
172 parsed_connection_spec parsed = parse_connection_spec (name, &hint);
173
174 if (parsed.port_str.empty ())
175 error (_("Missing port on hostname '%s'"), name);
c906108c 176
b80864fb 177#ifdef USE_WIN32API
c7ab0aef
SDJ
178 if (!winsock_initialized)
179 {
180 WSADATA wsad;
b80864fb 181
c7ab0aef
SDJ
182 WSAStartup (MAKEWORD (1, 0), &wsad);
183 winsock_initialized = 1;
184 }
b80864fb
DJ
185#endif
186
c7ab0aef
SDJ
187 int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (),
188 &hint, &ainfo);
c906108c 189
c7ab0aef
SDJ
190 if (r != 0)
191 {
192 fprintf (stderr, "%s:%s: cannot resolve name: %s\n",
193 parsed.host_str.c_str (), parsed.port_str.c_str (),
194 gai_strerror (r));
195 fflush (stderr);
196 exit (1);
197 }
198
199 scoped_free_addrinfo free_ainfo (ainfo);
200
201 struct addrinfo *p;
c906108c 202
c7ab0aef
SDJ
203 for (p = ainfo; p != NULL; p = p->ai_next)
204 {
205 tmp_desc = socket (p->ai_family, p->ai_socktype, p->ai_protocol);
206
207 if (tmp_desc >= 0)
208 break;
209 }
210
211 if (p == NULL)
212 perror_with_name ("Cannot open socket");
213
214 /* Allow rapid reuse of this port. */
215 tmp = 1;
216 setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
217 sizeof (tmp));
218
219 switch (p->ai_family)
220 {
221 case AF_INET:
222 ((struct sockaddr_in *) p->ai_addr)->sin_addr.s_addr = INADDR_ANY;
223 break;
224 case AF_INET6:
225 ((struct sockaddr_in6 *) p->ai_addr)->sin6_addr = in6addr_any;
226 break;
227 default:
228 fprintf (stderr, "Invalid 'ai_family' %d\n", p->ai_family);
229 exit (1);
230 }
c906108c 231
c7ab0aef
SDJ
232 if (bind (tmp_desc, p->ai_addr, p->ai_addrlen) != 0)
233 perror_with_name ("Can't bind address");
234
235 if (p->ai_socktype == SOCK_DGRAM)
236 remote_desc = tmp_desc;
237 else
238 {
239 struct sockaddr_storage sockaddr;
240 socklen_t sockaddrsize = sizeof (sockaddr);
241 char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT];
242
243 if (listen (tmp_desc, 1) != 0)
244 perror_with_name ("Can't listen on socket");
245
246 remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr,
247 &sockaddrsize);
c906108c 248
c906108c
SS
249 if (remote_desc == -1)
250 perror_with_name ("Accept failed");
251
c906108c
SS
252 /* Enable TCP keep alive process. */
253 tmp = 1;
493e2a69
MS
254 setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE,
255 (char *) &tmp, sizeof (tmp));
c906108c
SS
256
257 /* Tell TCP not to delay small packets. This greatly speeds up
1b3f6016 258 interactive response. */
c906108c 259 tmp = 1;
373fe97f 260 setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
c5aa993b 261 (char *) &tmp, sizeof (tmp));
c906108c 262
c7ab0aef
SDJ
263 if (getnameinfo ((struct sockaddr *) &sockaddr, sockaddrsize,
264 orig_host, sizeof (orig_host),
265 orig_port, sizeof (orig_port),
266 NI_NUMERICHOST | NI_NUMERICSERV) == 0)
267 {
268 fprintf (stderr, "Remote debugging from host %s, port %s\n",
269 orig_host, orig_port);
270 fflush (stderr);
271 }
272
b80864fb
DJ
273#ifndef USE_WIN32API
274 close (tmp_desc); /* No longer need this */
275
493e2a69
MS
276 signal (SIGPIPE, SIG_IGN); /* If we don't do this, then
277 gdbreplay simply exits when
278 the remote side dies. */
b80864fb
DJ
279#else
280 closesocket (tmp_desc); /* No longer need this */
281#endif
c906108c
SS
282 }
283
b80864fb 284#if defined(F_SETFL) && defined (FASYNC)
c906108c 285 fcntl (remote_desc, F_SETFL, FASYNC);
b80864fb 286#endif
c906108c
SS
287
288 fprintf (stderr, "Replay logfile using %s\n", name);
289 fflush (stderr);
290}
291
c5aa993b 292static int
909c2cda 293fromhex (int ch)
c906108c
SS
294{
295 if (ch >= '0' && ch <= '9')
296 {
297 return (ch - '0');
298 }
299 if (ch >= 'A' && ch <= 'F')
300 {
301 return (ch - 'A' + 10);
302 }
303 if (ch >= 'a' && ch <= 'f')
304 {
305 return (ch - 'a' + 10);
306 }
307 fprintf (stderr, "\nInvalid hex digit '%c'\n", ch);
308 fflush (stderr);
309 exit (1);
310}
311
312static int
fba45db2 313logchar (FILE *fp)
c906108c
SS
314{
315 int ch;
316 int ch2;
317
318 ch = fgetc (fp);
43ac54fc
TT
319 if (ch != '\r')
320 {
321 fputc (ch, stdout);
322 fflush (stdout);
323 }
c906108c
SS
324 switch (ch)
325 {
43ac54fc
TT
326 /* Treat \r\n as a newline. */
327 case '\r':
328 ch = fgetc (fp);
329 if (ch == '\n')
330 ch = EOL;
331 else
332 {
333 ungetc (ch, fp);
334 ch = '\r';
335 }
336 fputc (ch == EOL ? '\n' : '\r', stdout);
337 fflush (stdout);
338 break;
c906108c
SS
339 case '\n':
340 ch = EOL;
341 break;
342 case '\\':
343 ch = fgetc (fp);
344 fputc (ch, stdout);
345 fflush (stdout);
346 switch (ch)
347 {
c5aa993b
JM
348 case '\\':
349 break;
350 case 'b':
351 ch = '\b';
352 break;
353 case 'f':
354 ch = '\f';
355 break;
356 case 'n':
357 ch = '\n';
358 break;
359 case 'r':
360 ch = '\r';
361 break;
362 case 't':
363 ch = '\t';
364 break;
365 case 'v':
366 ch = '\v';
367 break;
c906108c
SS
368 case 'x':
369 ch2 = fgetc (fp);
370 fputc (ch2, stdout);
371 fflush (stdout);
909c2cda 372 ch = fromhex (ch2) << 4;
c906108c
SS
373 ch2 = fgetc (fp);
374 fputc (ch2, stdout);
375 fflush (stdout);
909c2cda 376 ch |= fromhex (ch2);
c906108c
SS
377 break;
378 default:
379 /* Treat any other char as just itself */
380 break;
381 }
382 default:
383 break;
384 }
385 return (ch);
386}
387
e581f2b4
PA
388static int
389gdbchar (int desc)
390{
391 unsigned char fromgdb;
392
393 if (read (desc, &fromgdb, 1) != 1)
394 return -1;
395 else
396 return fromgdb;
397}
398
c906108c
SS
399/* Accept input from gdb and match with chars from fp (after skipping one
400 blank) up until a \n is read from fp (which is not matched) */
401
82e0fd98 402static void
fba45db2 403expect (FILE *fp)
c906108c
SS
404{
405 int fromlog;
e581f2b4 406 int fromgdb;
c906108c
SS
407
408 if ((fromlog = logchar (fp)) != ' ')
409 {
410 sync_error (fp, "Sync error during gdb read of leading blank", ' ',
411 fromlog);
412 }
413 do
414 {
415 fromlog = logchar (fp);
416 if (fromlog == EOL)
e581f2b4
PA
417 break;
418 fromgdb = gdbchar (remote_desc);
419 if (fromgdb < 0)
420 remote_error ("Error during read from gdb");
c5aa993b
JM
421 }
422 while (fromlog == fromgdb);
e581f2b4 423
c906108c
SS
424 if (fromlog != EOL)
425 {
e581f2b4 426 sync_error (fp, "Sync error during read of gdb packet from log", fromlog,
c906108c
SS
427 fromgdb);
428 }
429}
430
431/* Play data back to gdb from fp (after skipping leading blank) up until a
432 \n is read from fp (which is discarded and not sent to gdb). */
433
82e0fd98 434static void
fba45db2 435play (FILE *fp)
c906108c
SS
436{
437 int fromlog;
438 char ch;
439
440 if ((fromlog = logchar (fp)) != ' ')
441 {
442 sync_error (fp, "Sync error skipping blank during write to gdb", ' ',
443 fromlog);
444 }
445 while ((fromlog = logchar (fp)) != EOL)
446 {
447 ch = fromlog;
e581f2b4
PA
448 if (write (remote_desc, &ch, 1) != 1)
449 remote_error ("Error during write to gdb");
c906108c
SS
450 }
451}
452
c16158bc
JM
453static void
454gdbreplay_version (void)
455{
456 printf ("GNU gdbreplay %s%s\n"
66d91b39 457 "Copyright (C) 2019 Free Software Foundation, Inc.\n"
493e2a69
MS
458 "gdbreplay is free software, covered by "
459 "the GNU General Public License.\n"
90aa6a40 460 "This gdbreplay was configured as \"%s\"\n",
c16158bc
JM
461 PKGVERSION, version, host_name);
462}
463
464static void
465gdbreplay_usage (FILE *stream)
466{
752312ba 467 fprintf (stream, "Usage:\tgdbreplay LOGFILE HOST:PORT\n");
c16158bc
JM
468 if (REPORT_BUGS_TO[0] && stream == stdout)
469 fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO);
470}
471
03349c93
PA
472/* Main function. This is called by the real "main" function,
473 wrapped in a TRY_CATCH that handles any uncaught exceptions. */
474
475static void ATTRIBUTE_NORETURN
476captured_main (int argc, char *argv[])
c906108c
SS
477{
478 FILE *fp;
479 int ch;
480
c16158bc
JM
481 if (argc >= 2 && strcmp (argv[1], "--version") == 0)
482 {
483 gdbreplay_version ();
484 exit (0);
485 }
486 if (argc >= 2 && strcmp (argv[1], "--help") == 0)
487 {
488 gdbreplay_usage (stdout);
489 exit (0);
490 }
491
c906108c
SS
492 if (argc < 3)
493 {
c16158bc 494 gdbreplay_usage (stderr);
c906108c
SS
495 exit (1);
496 }
497 fp = fopen (argv[1], "r");
498 if (fp == NULL)
499 {
500 perror_with_name (argv[1]);
c5aa993b 501 }
c906108c
SS
502 remote_open (argv[2]);
503 while ((ch = logchar (fp)) != EOF)
504 {
505 switch (ch)
506 {
507 case 'w':
508 /* data sent from gdb to gdbreplay, accept and match it */
509 expect (fp);
510 break;
511 case 'r':
512 /* data sent from gdbreplay to gdb, play it */
513 play (fp);
514 break;
515 case 'c':
516 /* Command executed by gdb */
517 while ((ch = logchar (fp)) != EOL);
518 break;
519 }
520 }
521 remote_close ();
522 exit (0);
523}
03349c93
PA
524
525int
526main (int argc, char *argv[])
527{
528 TRY
529 {
530 captured_main (argc, argv);
531 }
532 CATCH (exception, RETURN_MASK_ALL)
533 {
534 if (exception.reason == RETURN_ERROR)
535 {
536 fflush (stdout);
537 fprintf (stderr, "%s\n", exception.message);
538 }
539
540 exit (1);
541 }
542 END_CATCH
543
544 gdb_assert_not_reached ("captured_main should never return");
545}
This page took 1.432594 seconds and 4 git commands to generate.