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