From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20289 invoked by alias); 19 Mar 2004 18:29:53 -0000 Mailing-List: contact rda-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Post: List-Help: , Sender: rda-owner@sources.redhat.com Received: (qmail 20278 invoked from network); 19 Mar 2004 18:29:51 -0000 Date: Fri, 19 Mar 2004 18:29:00 -0000 From: Kevin Buettner To: rda@sources.redhat.com Subject: [PATCH] Add serial support for unix ports Message-Id: <20040319112945.12c240d6@saguaro> Organization: Red Hat X-Mailer: Sylpheed version 0.9.8claws30 (GTK+ 1.2.10; i686-pc-linux-gnu) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-SW-Source: 2004-q1/txt/msg00004.txt.bz2 I've just committed the patch below... * ptrace-target.c (ptrace_exit_program): Cause main loop to exit. * server.c (sys/types.h, sys/stat.h, fcntl.h, string.h, unistd.h) (ctype.h, termios.h): Include. (close_device, tty_raw, invalid_speed, parse_speed): New functions. (speed_table): New static global. (usage): Update usage message. (main): Add support for connecting to serial devices. Index: ptrace-target.c =================================================================== RCS file: /cvs/src/src/rda/unix/ptrace-target.c,v retrieving revision 1.5 diff -u -p -r1.5 ptrace-target.c --- ptrace-target.c 10 Mar 2004 17:56:43 -0000 1.5 +++ ptrace-target.c 19 Mar 2004 18:16:19 -0000 @@ -417,7 +417,9 @@ static void ptrace_exit_program (struct gdbserv *serv) { ptrace_sigkill_program (serv); - gdbserv_fromtarget_exit (serv, GDBSERV_SIGQUIT); + gdbserv_fromtarget_exit (serv, GDBSERV_SIGKILL); + /* Quit out of main loop. */ + server_quit_p = 1; } /* break program vector Index: server.c =================================================================== RCS file: /cvs/src/src/rda/unix/server.c,v retrieving revision 1.3 diff -u -p -r1.3 server.c --- server.c 10 Mar 2004 17:56:43 -0000 1.3 +++ server.c 19 Mar 2004 18:16:19 -0000 @@ -29,6 +29,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include "gdbsocket.h" #include "gdbloop.h" @@ -50,41 +57,239 @@ chld_handler (int sig) { } +static struct termios save_termios; + +static void +close_device (int infd, int outfd) +{ + if (isatty (infd)) + { + tcsetattr (infd, TCSAFLUSH, &save_termios); + } + close (infd); + close (outfd); +} + +/* Put a tty into "raw" mode. Mostly taken from Stevens' book, "Advanced + Programming in the UNIX Environment. */ +static int +tty_raw (int fd, speed_t speed) +{ + struct termios buf; + + /* Don't do anything for non-tty devices. */ + if (!isatty (fd)) + return 0; + + if (tcgetattr (fd, &save_termios) < 0) + return -1; + + buf = save_termios; + + /* Set the following local modes: echo off, canonical mode off, extended + input processing off, signal chars off. */ + buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + + /* Set the following input modes: no SIGINT on BREAK, CR-to-NL off, input + parity check off, don't strip 7th bit on input, output flow control + off. */ + buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + + /* Set the following control modes: clear size bits, parity checking off. */ + buf.c_cflag &= ~(CSIZE | PARENB); + + /* Enable 8 bits/char. */ + buf.c_cflag |= CS8; + + /* Turn output processing off. */ + buf.c_oflag &= ~(OPOST); + + /* Case B: 1 byte at a time, no timer */ + buf.c_cc[VMIN] = 1; + buf.c_cc[VTIME] = 0; + + if (speed != 0) + { + cfsetispeed (&buf, speed); + cfsetospeed (&buf, speed); + } + + if (tcsetattr(fd, TCSAFLUSH, &buf) < 0) + return -1; + return 0; +} + +/* Table of serial port speed values. */ +static struct + { + long speed; /* speed value as an integer */ + speed_t bspeed; /* speed value as one of the termios.h constants + suitable for passing to cfsetispeed() or + cfsetospeed(). */ + } +speed_table[] = { + { 50, B50 }, + { 75, B75 }, + { 110, B110 }, + { 134, B134 }, + { 150, B150 }, + { 200, B200 }, + { 300, B300 }, + { 600, B600 }, + { 1200, B1200 }, + { 1800, B1800 }, + { 2400, B2400 }, + { 4800, B4800 }, + { 9600, B9600 }, + { 19200, B19200 }, + { 38400, B38400 } +#ifdef B57600 + ,{ 57600, B57600 } +#endif +#ifdef B115200 + ,{ 115200, B115200 } +#endif +#ifdef B230400 + ,{ 230400, B230400 } +#endif +#ifdef B460800 + ,{ 460800, B460800 } +#endif +#ifdef B500000 + ,{ 500000, B500000 } +#endif +#ifdef B576000 + ,{ 576000, B576000 } +#endif +#ifdef B921600 + ,{ 921600, B921600 } +#endif +#ifdef B2000000 + ,{ 1000000, B1000000 } +#endif +#ifdef B1152000 + ,{ 1152000, B1152000 } +#endif +#ifdef B1500000 + ,{ 1500000, B1500000 } +#endif +#ifdef B2000000 + ,{ 2000000, B2000000 } +#endif +#ifdef B2500000 + ,{ 2500000, B2500000 } +#endif +#ifdef B3000000 + ,{ 3000000, B3000000 } +#endif +#ifdef B3500000 + ,{ 3500000, B3500000 } +#endif +#ifdef B4000000 + ,{ 4000000, B4000000 } +#endif +}; + +/* Print error for erroneous -s switch and exit. */ +static void +invalid_speed (char *str) +{ + int i; + int ll; + + fprintf (stderr, "Error: Invalid -s switch \"%s\".\n", str); + ll = fprintf (stderr, "Valid speeds are:"); + + for (i = 0; i < sizeof (speed_table) / sizeof (speed_table[0]); i++) + { + char str[20]; + int cnt; + cnt = snprintf (str, sizeof (str), "%d", speed_table[i].speed); + if (cnt + ll + 1 > 80) + { + fprintf (stderr, "\n"); + ll = 0; + } + else + { + fprintf (stderr, " "); + ll++; + } + fprintf (stderr, "%s", str); + ll += cnt; + } + fprintf (stderr, "\n"); + exit (1); +} + +/* Attempt to parse a speed and return the speed value. */ +static speed_t +parse_speed (char *str) +{ + int i; + long speed; + char *endptr; + + speed = strtol (str, &endptr, 10); + if (speed == 0 || *endptr != '\0') + { + invalid_speed (str); + /* won't return */ + } + + for (i = 0; i < sizeof (speed_table) / sizeof (speed_table[0]); i++) + if (speed_table[i].speed == speed) + return speed_table[i].bspeed; + + /* Speed not found. Error out. */ + invalid_speed (str); + return 0; /* won't actually return */ +} + /* Print a usage message and exit. */ static void usage (char *progname) { fprintf (stderr, - "Usage: %s [-h] [-v] tcp-port-num executable-file [arguments ...]\n" - " or: %s -a [-v] tcp-port-num process-id\n\n" - "Start the Red Hat debug agent listening on port ``tcp-port-num'' for\n" - "debugging``executable-file'' with optional arguments.\n\n" + "Usage: %s [-v] tcp-port-num executable-file [arguments ...]\n" + " or: %s -a [-v] tcp-port-num process-id\n" + " or: %s [-v] [-s speed] device-name executable-file [arguments ...]\n" + " or: %s -a [-v] [-s speed] device-name process-id\n" + " or: %s -h\n" + "Start the Red Hat debug agent for use with a remote debugger.\n" "Options and arguments:\n" " -a Attach to already running process.\n" " -h Print this usage message.\n" + " -s speed Set speed (e.g. 115200) at which device \"device-name\"\n" + " will communicate with remote debugger.\n" " -v Increase verbosity. One -v flag enables informational\n" " messages. Two -v flags turn on internal debugging\n" " messages.\n" - " tcp-port-num Port number to which debugger connects for purpose\n" - " of communicating with the debug agent using the GDB\n" - " remote protocol.\n" - " executable-file Name of program to debug.\n" " arguments ... Command line arguments with which to start program\n" " being debugged.\n" - " process-id Process ID (PID) of process to attach to.\n", - progname, progname); + " device-name Name of serial device over which RDA will communicate\n" + " with remote debugger.\n" + " executable-file Name of program to debug.\n" + " process-id Process ID (PID) of process to attach to.\n" + " tcp-port-num Port number to which debugger connects for purpose\n" + " of communicating with the debug agent using the GDB\n" + " remote protocol.\n", + progname, progname, progname, progname, progname); exit (1); } int main (int argc, char **argv) { - int portno; + int portno = 0; char *endptr; int verbose = 0; int attach = 0; int optidx; + int infd, outfd; struct child_process *process; + char *devicename = ""; + speed_t speed; /* Parse options. */ for (optidx = 1; optidx < argc; optidx++) @@ -100,6 +305,12 @@ main (int argc, char **argv) usage (argv[0]); /* not reached */ break; + case 's': + optidx++; + if (optidx >= argc) + usage(argv[0]); + speed = parse_speed (argv[optidx]); + break; case 'v': verbose++; break; @@ -116,10 +327,31 @@ main (int argc, char **argv) if (argc - optidx < 2) usage (argv[0]); - errno = 0; - portno = strtol (argv[optidx], &endptr, 10); - if (errno != 0 || endptr == argv[optidx]) - usage (argv[0]); + if (isdigit (*argv[optidx])) + { + errno = 0; + portno = strtol (argv[optidx], &endptr, 10); + if (errno != 0 || portno == 0) + usage (argv[0]); + } + else if (strcmp (argv[optidx], "-") == 0) + { + infd = STDIN_FILENO; + outfd = STDOUT_FILENO; + devicename = "stdin/stdout"; + } + else + { + devicename = argv[optidx]; + infd = open (devicename, O_RDWR); + if (infd < 0) + { + fprintf (stderr, "Error opening device %s: %s\n", devicename, + strerror (errno)); + exit (1); + } + outfd = infd; + } process = malloc (sizeof (struct child_process)); memset (process, 0, sizeof (struct child_process)); @@ -142,9 +374,19 @@ main (int argc, char **argv) signal (SIGCHLD, chld_handler); - gdbsocket_startup (portno, gdbserver.attach, process); - if (process->debug_informational) - fprintf (stderr, "Started listening socket on port %d.\n", portno); + if (portno != 0) + { + gdbsocket_startup (portno, gdbserver.attach, process); + if (process->debug_informational) + fprintf (stderr, "Started listening socket on port %d.\n", portno); + } + else + { + tty_raw (infd, speed); + if (process->debug_informational) + fprintf (stderr, "Waiting for input on %s.\n", devicename); + gdbsocket_reopen (infd, outfd, close_device, gdbserver.attach, process); + } /* Poll for socket traffic. */ while (! server_quit_p)