3 Copyright 2000, 2001, 2002 Red Hat, Inc.
5 This file is part of RDA, the Red Hat Debug Agent (and library).
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
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Alternative licenses for RDA may be arranged by contacting Red Hat,
32 #include <sys/types.h>
40 #include "gdbsocket.h"
45 /* Signal a request to terminate main loop. */
46 int server_quit_p = 0;
48 /* FIXME -- move to header file. */
49 struct gdbserv_target *linux_attach (struct gdbserv* serv, void* data);
51 /* We have an empty SIGCHLD handler in order to make sure that
52 the timed, but blocking call to select will be interrupted
53 by SIGCHLD signals. */
56 chld_handler (int sig)
60 static struct termios save_termios;
63 close_device (int infd, int outfd)
67 tcsetattr (infd, TCSAFLUSH, &save_termios);
73 /* Put a tty into "raw" mode. Mostly taken from Stevens' book, "Advanced
74 Programming in the UNIX Environment. */
76 tty_raw (int fd, speed_t speed)
80 /* Don't do anything for non-tty devices. */
84 if (tcgetattr (fd, &save_termios) < 0)
89 /* Set the following local modes: echo off, canonical mode off, extended
90 input processing off, signal chars off. */
91 buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
93 /* Set the following input modes: no SIGINT on BREAK, CR-to-NL off, input
94 parity check off, don't strip 7th bit on input, output flow control
96 buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
98 /* Set the following control modes: clear size bits, parity checking off. */
99 buf.c_cflag &= ~(CSIZE | PARENB);
101 /* Enable 8 bits/char. */
104 /* Turn output processing off. */
105 buf.c_oflag &= ~(OPOST);
107 /* Case B: 1 byte at a time, no timer */
113 cfsetispeed (&buf, speed);
114 cfsetospeed (&buf, speed);
117 if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
122 /* Table of serial port speed values. */
125 long speed; /* speed value as an integer */
126 speed_t bspeed; /* speed value as one of the termios.h constants
127 suitable for passing to cfsetispeed() or
168 ,{ 1000000, B1000000 }
171 ,{ 1152000, B1152000 }
174 ,{ 1500000, B1500000 }
177 ,{ 2000000, B2000000 }
180 ,{ 2500000, B2500000 }
183 ,{ 3000000, B3000000 }
186 ,{ 3500000, B3500000 }
189 ,{ 4000000, B4000000 }
193 /* Print error for erroneous -s switch and exit. */
195 invalid_speed (char *str)
200 fprintf (stderr, "Error: Invalid -s switch \"%s\".\n", str);
201 ll = fprintf (stderr, "Valid speeds are:");
203 for (i = 0; i < sizeof (speed_table) / sizeof (speed_table[0]); i++)
207 cnt = snprintf (str, sizeof (str), "%ld", speed_table[i].speed);
208 if (cnt + ll + 1 > 80)
210 fprintf (stderr, "\n");
215 fprintf (stderr, " ");
218 fprintf (stderr, "%s", str);
221 fprintf (stderr, "\n");
225 /* Attempt to parse a speed and return the speed value. */
227 parse_speed (char *str)
233 speed = strtol (str, &endptr, 10);
234 if (speed == 0 || *endptr != '\0')
240 for (i = 0; i < sizeof (speed_table) / sizeof (speed_table[0]); i++)
241 if (speed_table[i].speed == speed)
242 return speed_table[i].bspeed;
244 /* Speed not found. Error out. */
246 return 0; /* won't actually return */
249 /* Print a usage message and exit. */
251 usage (char *progname)
253 /* Remove any leading slashes from the executable name. */
254 if (strrchr (progname, '/'))
255 progname = strrchr (progname, '/') + 1;
258 "Usage: %s [-v] tcp-port-num executable-file [arguments ...]\n"
259 " or: %s -a [-v] tcp-port-num process-id\n"
260 " or: %s [-v] [-s speed] device-name executable-file [arguments ...]\n"
261 " or: %s -a [-v] [-s speed] device-name process-id\n"
263 "Start the Red Hat debug agent for use with a remote debugger.\n"
264 "Options and arguments:\n"
265 " -a Attach to already running process.\n"
266 " -h Print this usage message.\n"
267 " -s speed Set speed (e.g. 115200) at which device \"device-name\"\n"
268 " will communicate with remote debugger.\n"
269 " -v Increase verbosity. One -v flag enables informational\n"
270 " messages. Two -v flags turn on internal debugging\n"
272 " arguments ... Command line arguments with which to start program\n"
274 " device-name Name of serial device over which RDA will communicate\n"
275 " with remote debugger.\n"
276 " executable-file Name of program to debug.\n"
277 " process-id Process ID (PID) of process to attach to.\n"
278 " tcp-port-num Port number to which debugger connects for purpose\n"
279 " of communicating with the debug agent using the GDB\n"
280 " remote protocol.\n",
281 progname, progname, progname, progname, progname);
286 main (int argc, char **argv)
293 int infd = 0, outfd = 0;
294 struct child_process *process;
295 char *devicename = "";
299 for (optidx = 1; optidx < argc; optidx++)
301 if (argv[optidx][0] == '-' && argv[optidx][1] != '\0')
303 switch (argv[optidx][1])
316 speed = parse_speed (argv[optidx]);
331 if (argc - optidx < 2)
334 if (isdigit (*argv[optidx]))
337 portno = strtol (argv[optidx], &endptr, 10);
338 if (errno != 0 || portno == 0)
341 else if (strcmp (argv[optidx], "-") == 0)
344 outfd = STDOUT_FILENO;
345 devicename = "stdin/stdout";
349 devicename = argv[optidx];
350 infd = open (devicename, O_RDWR);
353 fprintf (stderr, "Error opening device %s: %s\n", devicename,
360 process = malloc (sizeof (struct child_process));
361 memset (process, 0, sizeof (struct child_process));
364 process->pid = strtol (argv[optidx + 1], &endptr, 10);
365 if (errno != 0 || endptr == argv[optidx] || process->pid <= 0)
370 process->argv = &argv[optidx + 1];
371 process->executable = argv[optidx + 1];
375 process->debug_backend = 1;
377 process->debug_informational = 1;
379 signal (SIGCHLD, chld_handler);
381 #if defined(__SIGRTMIN) && defined(__SIGRTMAX)
384 /* Ignore realtime signals. We do this so as to not terminate
385 RDA if we inadvertently receive one of these signals. The
386 realtime signals are used for thread support, and, for some
387 reason, some environments send these signals to RDA as well
388 as the application. (And some don't.) */
389 for (sig = __SIGRTMIN; sig <= __SIGRTMAX; sig++)
390 signal (sig, SIG_IGN);
396 if (gdbsocket_startup (portno, gdbserver.attach, process) < 0)
398 fprintf (stderr, "Error listening on port %d: %s\n",
399 portno, strerror (errno));
402 if (process->debug_informational)
403 fprintf (stderr, "Started listening socket on port %d.\n", portno);
407 tty_raw (infd, speed);
408 if (process->debug_informational)
409 fprintf (stderr, "Waiting for input on %s.\n", devicename);
410 gdbsocket_reopen (infd, outfd, close_device, gdbserver.attach, process);
413 /* Poll for socket traffic. */
414 while (! server_quit_p)
416 gdbloop_poll (1 /* second */);
419 if (gdbserver.check_child_state (process))
421 switch (process->stop_status) {
423 gdbserver.fromtarget_break (process);
426 gdbserver.fromtarget_terminate (process);
427 server_quit_p = 1; /* See below. */
430 gdbserver.fromtarget_exit (process);
431 /* If we're connected to a serial port which is not
432 observing the modem control signals (e.g. "stty
433 clocal"), then we'll never notice that the port has
434 been closed. For this reason, when we notice that
435 the target has exited or terminated, we need to set
436 ``server_quit_p'' explicitly. */
443 gdbsocket_shutdown ();
444 if (process->debug_informational)
445 fprintf (stderr, "Shut down sockets.\n");