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