X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fser-unix.c;h=9a13acddbc85a75a45e5ec62e816e4b9af9f361d;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-batching;hp=eb34da5de7ff1c413af3faa0ba1f563dae3484dc;hpb=68d2db622d49c606fcd61e7e1253aaf05c089e41;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c index eb34da5de7..9a13acddbc 100644 --- a/gdb/ser-unix.c +++ b/gdb/ser-unix.c @@ -1,85 +1,81 @@ /* Serial interface for local (hardwired) serial ports on Un*x like systems - Copyright 1992, 1993 Free Software Foundation, Inc. -This file is part of GDB. + Copyright (C) 1992-2020 Free Software Foundation, Inc. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This file is part of GDB. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "defs.h" #include "serial.h" +#include "ser-base.h" +#include "ser-unix.h" + #include #include +#include "terminal.h" +#include +#include "gdbsupport/gdb_sys_time.h" -#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY) -#define HAVE_SGTTY -#endif - -#ifdef HAVE_TERMIOS +#include "gdbsupport/gdb_select.h" +#include "gdbcmd.h" +#include "gdbsupport/filestuff.h" #include -#include - -struct hardwire_ttystate -{ - struct termios termios; -}; -#endif - -#ifdef HAVE_TERMIO -#include +#include "inflow.h" struct hardwire_ttystate -{ - struct termio termio; -}; -#endif - -#ifdef HAVE_SGTTY -/* Needed for the code which uses select(). We would include - too if it existed on all systems. */ -#include - -#include + { + struct termios termios; + }; -struct hardwire_ttystate +#ifdef CRTSCTS +/* Boolean to explicitly enable or disable h/w flow control. */ +static bool serial_hwflow; +static void +show_serial_hwflow (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) { - struct sgttyb sgttyb; -}; + fprintf_filtered (file, _("Hardware flow control is %s.\n"), value); +} #endif -static int hardwire_open PARAMS ((serial_t scb, const char *name)); -static void hardwire_raw PARAMS ((serial_t scb)); -static int wait_for PARAMS ((serial_t scb, int timeout)); -static int hardwire_readchar PARAMS ((serial_t scb, int timeout)); -static int rate_to_code PARAMS ((int rate)); -static int hardwire_setbaudrate PARAMS ((serial_t scb, int rate)); -static int hardwire_write PARAMS ((serial_t scb, const char *str, int len)); -static void hardwire_restore PARAMS ((serial_t scb)); -static void hardwire_close PARAMS ((serial_t scb)); -static int get_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state)); -static int set_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state)); -static serial_ttystate hardwire_get_tty_state PARAMS ((serial_t scb)); -static int hardwire_set_tty_state PARAMS ((serial_t scb, serial_ttystate state)); - -/* Open up a real live device for serial I/O */ +static int hardwire_open (struct serial *scb, const char *name); +static void hardwire_raw (struct serial *scb); +static int rate_to_code (int rate); +static int hardwire_setbaudrate (struct serial *scb, int rate); +static int hardwire_setparity (struct serial *scb, int parity); +static void hardwire_close (struct serial *scb); +static int get_tty_state (struct serial *scb, + struct hardwire_ttystate * state); +static int set_tty_state (struct serial *scb, + struct hardwire_ttystate * state); +static serial_ttystate hardwire_get_tty_state (struct serial *scb); +static int hardwire_set_tty_state (struct serial *scb, serial_ttystate state); +static void hardwire_print_tty_state (struct serial *, serial_ttystate, + struct ui_file *); +static int hardwire_drain_output (struct serial *); +static int hardwire_flush_output (struct serial *); +static int hardwire_flush_input (struct serial *); +static int hardwire_send_break (struct serial *); +static int hardwire_setstopbits (struct serial *, int); + +/* Open up a real live device for serial I/O. */ static int -hardwire_open(scb, name) - serial_t scb; - const char *name; +hardwire_open (struct serial *scb, const char *name) { - scb->fd = open (name, O_RDWR); + scb->fd = gdb_open_cloexec (name, O_RDWR, 0); if (scb->fd < 0) return -1; @@ -87,215 +83,147 @@ hardwire_open(scb, name) } static int -get_tty_state(scb, state) - serial_t scb; - struct hardwire_ttystate *state; +get_tty_state (struct serial *scb, struct hardwire_ttystate *state) { -#ifdef HAVE_TERMIOS - return tcgetattr(scb->fd, &state->termios); -#endif - -#ifdef HAVE_TERMIO - return ioctl (scb->fd, TCGETA, &state->termio); -#endif + if (tcgetattr (scb->fd, &state->termios) < 0) + return -1; -#ifdef HAVE_SGTTY - return ioctl (scb->fd, TIOCGETP, &state->sgttyb); -#endif + return 0; } static int -set_tty_state(scb, state) - serial_t scb; - struct hardwire_ttystate *state; +set_tty_state (struct serial *scb, struct hardwire_ttystate *state) { - int err; + if (tcsetattr (scb->fd, TCSANOW, &state->termios) < 0) + return -1; -#ifdef HAVE_TERMIOS - return tcsetattr(scb->fd, TCSANOW, &state->termios); -#endif + return 0; +} -#ifdef HAVE_TERMIO - return ioctl (scb->fd, TCSETA, &state->termio); -#endif +static serial_ttystate +hardwire_get_tty_state (struct serial *scb) +{ + struct hardwire_ttystate *state = XNEW (struct hardwire_ttystate); -#ifdef HAVE_SGTTY - return ioctl (scb->fd, TIOCSETP, &state->sgttyb); -#endif + if (get_tty_state (scb, state)) + { + xfree (state); + return NULL; + } + + return (serial_ttystate) state; } static serial_ttystate -hardwire_get_tty_state(scb) - serial_t scb; +hardwire_copy_tty_state (struct serial *scb, serial_ttystate ttystate) { - struct hardwire_ttystate *state; - - state = (struct hardwire_ttystate *)xmalloc(sizeof *state); + struct hardwire_ttystate *state = XNEW (struct hardwire_ttystate); - if (get_tty_state(scb, state)) - return NULL; + *state = *(struct hardwire_ttystate *) ttystate; - return (serial_ttystate)state; + return (serial_ttystate) state; } static int -hardwire_set_tty_state(scb, ttystate) - serial_t scb; - serial_ttystate ttystate; +hardwire_set_tty_state (struct serial *scb, serial_ttystate ttystate) { struct hardwire_ttystate *state; - state = (struct hardwire_ttystate *)ttystate; + state = (struct hardwire_ttystate *) ttystate; - return set_tty_state(scb, state); + return set_tty_state (scb, state); } static void -hardwire_raw(scb) - serial_t scb; +hardwire_print_tty_state (struct serial *scb, + serial_ttystate ttystate, + struct ui_file *stream) { - struct hardwire_ttystate state; - - if (get_tty_state(scb, &state)) - fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno)); - -#ifdef HAVE_TERMIOS - state.termios.c_iflag = 0; - state.termios.c_oflag = 0; - state.termios.c_lflag = 0; - state.termios.c_cflag &= ~(CSIZE|PARENB); - state.termios.c_cflag |= CS8; - state.termios.c_cc[VMIN] = 0; - state.termios.c_cc[VTIME] = 0; -#endif - -#ifdef HAVE_TERMIO - state.termio.c_iflag = 0; - state.termio.c_oflag = 0; - state.termio.c_lflag = 0; - state.termio.c_cflag &= ~(CSIZE|PARENB); - state.termio.c_cflag |= CS8; - state.termio.c_cc[VMIN] = 0; - state.termio.c_cc[VTIME] = 0; -#endif + struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate; + int i; -#ifdef HAVE_SGTTY - state.sgttyb.sg_flags |= RAW | ANYP; - state.sgttyb.sg_flags &= ~(CBREAK | ECHO); + fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n", + (int) state->termios.c_iflag, + (int) state->termios.c_oflag); + fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x\n", + (int) state->termios.c_cflag, + (int) state->termios.c_lflag); +#if 0 + /* This not in POSIX, and is not really documented by those systems + which have it (at least not Sun). */ + fprintf_filtered (stream, "c_line = 0x%x.\n", state->termios.c_line); #endif - - scb->current_timeout = 0; - - if (set_tty_state (scb, &state)) - fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno)); + fprintf_filtered (stream, "c_cc: "); + for (i = 0; i < NCCS; i += 1) + fprintf_filtered (stream, "0x%x ", state->termios.c_cc[i]); + fprintf_filtered (stream, "\n"); } -/* Wait for input on scb, with timeout seconds. Returns 0 on success, - otherwise SERIAL_TIMEOUT or SERIAL_ERROR. - - For termio{s}, we actually just setup VTIME if necessary, and let the - timeout occur in the read() in hardwire_read(). - */ +/* Wait for the output to drain away, as opposed to flushing + (discarding) it. */ static int -wait_for(scb, timeout) - serial_t scb; - int timeout; +hardwire_drain_output (struct serial *scb) { - int numfds; - -#ifdef HAVE_SGTTY - struct timeval tv; - fd_set readfds; - - FD_ZERO (&readfds); + /* Ignore SIGTTOU which may occur during the drain. */ + scoped_ignore_sigttou ignore_sigttou; - tv.tv_sec = timeout; - tv.tv_usec = 0; - - FD_SET(scb->fd, &readfds); - - while (1) - { - if (timeout >= 0) - numfds = select(scb->fd+1, &readfds, 0, 0, &tv); - else - numfds = select(scb->fd+1, &readfds, 0, 0, 0); - - if (numfds <= 0) - if (numfds == 0) - return SERIAL_TIMEOUT; - else if (errno == EINTR) - continue; - else - return SERIAL_ERROR; /* Got an error from select or poll */ - - return 0; - } - -#endif /* HAVE_SGTTY */ - -#if defined HAVE_TERMIO || defined HAVE_TERMIOS - if (timeout == scb->current_timeout) - return 0; - - { - struct hardwire_ttystate state; - - if (get_tty_state(scb, &state)) - fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno)); - -#ifdef HAVE_TERMIOS - state.termios.c_cc[VTIME] = timeout * 10; -#endif - -#ifdef HAVE_TERMIO - state.termio.c_cc[VTIME] = timeout * 10; -#endif - - scb->current_timeout = timeout; - - if (set_tty_state (scb, &state)) - fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno)); - - return 0; - } -#endif /* HAVE_TERMIO || HAVE_TERMIOS */ + return tcdrain (scb->fd); } -/* Read a character with user-specified timeout. TIMEOUT is number of seconds - to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns - char if successful. Returns -2 if timeout expired, EOF if line dropped - dead, or -3 for any other error (see errno in that case). */ +static int +hardwire_flush_output (struct serial *scb) +{ + return tcflush (scb->fd, TCOFLUSH); +} static int -hardwire_readchar(scb, timeout) - serial_t scb; - int timeout; +hardwire_flush_input (struct serial *scb) { - int status; + ser_base_flush_input (scb); - if (scb->bufcnt-- > 0) - return *scb->bufp++; + return tcflush (scb->fd, TCIFLUSH); +} - status = wait_for(scb, timeout); +static int +hardwire_send_break (struct serial *scb) +{ + return tcsendbreak (scb->fd, 0); +} - if (status < 0) - return status; +static void +hardwire_raw (struct serial *scb) +{ + struct hardwire_ttystate state; - scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ); + if (get_tty_state (scb, &state)) + fprintf_unfiltered (gdb_stderr, "get_tty_state failed: %s\n", + safe_strerror (errno)); - if (scb->bufcnt <= 0) - if (scb->bufcnt == 0) - return SERIAL_TIMEOUT; /* 0 chars means timeout [may need to - distinguish between EOF & timeouts - someday] */ - else - return SERIAL_ERROR; /* Got an error from read */ + state.termios.c_iflag = 0; + state.termios.c_oflag = 0; + state.termios.c_lflag = 0; + state.termios.c_cflag &= ~CSIZE; + state.termios.c_cflag |= CLOCAL | CS8; +#ifdef CRTSCTS + /* h/w flow control. */ + if (serial_hwflow) + state.termios.c_cflag |= CRTSCTS; + else + state.termios.c_cflag &= ~CRTSCTS; +#ifdef CRTS_IFLOW + if (serial_hwflow) + state.termios.c_cflag |= CRTS_IFLOW; + else + state.termios.c_cflag &= ~CRTS_IFLOW; +#endif +#endif + state.termios.c_cc[VMIN] = 0; + state.termios.c_cc[VTIME] = 0; - scb->bufcnt--; - scb->bufp = scb->buf; - return *scb->bufp++; + if (set_tty_state (scb, &state)) + fprintf_unfiltered (gdb_stderr, "set_tty_state failed: %s\n", + safe_strerror (errno)); } #ifndef B19200 @@ -316,116 +244,287 @@ static struct } baudtab[] = { - {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}, - {-1, -1}, + { + 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 + { + -1, -1 + } + , }; -static int -rate_to_code(rate) - int rate; +static int +rate_to_code (int rate) { int i; for (i = 0; baudtab[i].rate != -1; i++) - if (rate == baudtab[i].rate) - return baudtab[i].code; - + { + /* test for perfect macth. */ + if (rate == baudtab[i].rate) + return baudtab[i].code; + else + { + /* check if it is in between valid values. */ + if (rate < baudtab[i].rate) + { + if (i) + { + warning (_("Invalid baud rate %d. " + "Closest values are %d and %d."), + rate, baudtab[i - 1].rate, baudtab[i].rate); + } + else + { + warning (_("Invalid baud rate %d. Minimum value is %d."), + rate, baudtab[0].rate); + } + return -1; + } + } + } + + /* The requested speed was too large. */ + warning (_("Invalid baud rate %d. Maximum value is %d."), + rate, baudtab[i - 1].rate); return -1; } static int -hardwire_setbaudrate(scb, rate) - serial_t scb; - int rate; +hardwire_setbaudrate (struct serial *scb, int rate) { struct hardwire_ttystate state; + int baud_code = rate_to_code (rate); + + if (baud_code < 0) + { + /* The baud rate was not valid. + A warning has already been issued. */ + errno = EINVAL; + return -1; + } - if (get_tty_state(scb, &state)) + if (get_tty_state (scb, &state)) return -1; -#ifdef HAVE_TERMIOS - cfsetospeed (&state.termios, rate_to_code (rate)); - cfsetispeed (&state.termios, rate_to_code (rate)); -#endif + cfsetospeed (&state.termios, baud_code); + cfsetispeed (&state.termios, baud_code); -#ifdef HAVE_TERMIO -#ifndef CIBAUD -#define CIBAUD CBAUD -#endif + return set_tty_state (scb, &state); +} - state.termio.c_cflag &= ~(CBAUD | CIBAUD); - state.termio.c_cflag |= rate_to_code (rate); -#endif +static int +hardwire_setstopbits (struct serial *scb, int num) +{ + struct hardwire_ttystate state; + int newbit; -#ifdef HAVE_SGTTY - state.sgttyb.sg_ispeed = rate_to_code (rate); - state.sgttyb.sg_ospeed = rate_to_code (rate); -#endif + if (get_tty_state (scb, &state)) + return -1; + + switch (num) + { + case SERIAL_1_STOPBITS: + newbit = 0; + break; + case SERIAL_1_AND_A_HALF_STOPBITS: + case SERIAL_2_STOPBITS: + newbit = 1; + break; + default: + return 1; + } + + if (!newbit) + state.termios.c_cflag &= ~CSTOPB; + else + state.termios.c_cflag |= CSTOPB; /* two bits */ return set_tty_state (scb, &state); } +/* Implement the "setparity" serial_ops callback. */ + static int -hardwire_write(scb, str, len) - serial_t scb; - const char *str; - int len; +hardwire_setparity (struct serial *scb, int parity) { - int cc; + struct hardwire_ttystate state; + int newparity = 0; - while (len > 0) - { - cc = write(scb->fd, str, len); + if (get_tty_state (scb, &state)) + return -1; - if (cc < 0) - return 1; - len -= cc; - str += cc; + switch (parity) + { + case GDBPARITY_NONE: + newparity = 0; + break; + case GDBPARITY_ODD: + newparity = PARENB | PARODD; + break; + case GDBPARITY_EVEN: + newparity = PARENB; + break; + default: + internal_warning (__FILE__, __LINE__, + "Incorrect parity value: %d", parity); + return -1; } - return 0; + + state.termios.c_cflag &= ~(PARENB | PARODD); + state.termios.c_cflag |= newparity; + + return set_tty_state (scb, &state); } + static void -hardwire_close(scb) - serial_t scb; +hardwire_close (struct serial *scb) { if (scb->fd < 0) return; - close(scb->fd); + close (scb->fd); scb->fd = -1; } + + + +/* The hardwire ops. */ -static struct serial_ops hardwire_ops = +static const struct serial_ops hardwire_ops = { "hardwire", - 0, hardwire_open, hardwire_close, - hardwire_readchar, - hardwire_write, + NULL, + ser_base_readchar, + ser_base_write, + hardwire_flush_output, + hardwire_flush_input, + hardwire_send_break, hardwire_raw, hardwire_get_tty_state, + hardwire_copy_tty_state, hardwire_set_tty_state, + hardwire_print_tty_state, hardwire_setbaudrate, + hardwire_setstopbits, + hardwire_setparity, + hardwire_drain_output, + ser_base_async, + ser_unix_read_prim, + ser_unix_write_prim }; +void _initialize_ser_hardwire (); void _initialize_ser_hardwire () { serial_add_interface (&hardwire_ops); + +#ifdef CRTSCTS + add_setshow_boolean_cmd ("remoteflow", no_class, + &serial_hwflow, _("\ +Set use of hardware flow control for remote serial I/O."), _("\ +Show use of hardware flow control for remote serial I/O."), _("\ +Enable or disable hardware flow control (RTS/CTS) on the serial port\n\ +when debugging using remote targets."), + NULL, + show_serial_hwflow, + &setlist, &showlist); +#endif +} + +int +ser_unix_read_prim (struct serial *scb, size_t count) +{ + return read (scb->fd, scb->buf, count); +} + +int +ser_unix_write_prim (struct serial *scb, const void *buf, size_t len) +{ + return write (scb->fd, buf, len); }