From 7e20166848e4acfbee695ff7eee3e22f3f3a33bf Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Tue, 10 Sep 2024 21:04:41 +0700 Subject: [PATCH] gdb: unix: allow to use custom baud rate --- gdb/config.in | 6 ++ gdb/configure | 6 +- gdb/configure.ac | 2 + gdb/ser-unix.c | 157 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 165 insertions(+), 6 deletions(-) diff --git a/gdb/config.in b/gdb/config.in index db63aeaec75..884225ca098 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -93,6 +93,9 @@ /* Define if amd-dbgapi is being linked in. */ #undef HAVE_AMD_DBGAPI +/* Define to 1 if you have the header file. */ +#undef HAVE_ASM_TERMIOS_H + /* Define to 1 if you have the `btowc' function. */ #undef HAVE_BTOWC @@ -241,6 +244,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_IOKIT_SERIAL_IOSS_H + /* Define to 1 if you have the `kinfo_getfile' function. */ #undef HAVE_KINFO_GETFILE diff --git a/gdb/configure b/gdb/configure index 7f9fc7fad54..bc6cceef6b5 100755 --- a/gdb/configure +++ b/gdb/configure @@ -11504,7 +11504,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11503 "configure" +#line 11507 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11610,7 +11610,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11609 "configure" +#line 11613 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -29228,6 +29228,8 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi for ac_header in \ + asm/termios.h \ + IOKit/serial/ioss.h \ machine/reg.h \ nlist.h \ ptrace.h \ diff --git a/gdb/configure.ac b/gdb/configure.ac index cc8a6a9cef3..9a6aeb93aa1 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1332,6 +1332,8 @@ AC_SUBST(SRCHIGH_CFLAGS) AC_HEADER_STDC AC_CHECK_HEADERS([ \ + asm/termios.h \ + IOKit/serial/ioss.h \ machine/reg.h \ nlist.h \ ptrace.h \ diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c index 02845aa938b..f4873e0f2d2 100644 --- a/gdb/ser-unix.c +++ b/gdb/ser-unix.c @@ -30,9 +30,30 @@ #include "gdbsupport/gdb_select.h" #include "cli/cli-cmds.h" #include "gdbsupport/filestuff.h" +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#if HAVE_IOKIT_SERIAL_IOSS_H +#include +#endif +#if HAVE_ASM_TERMIOS_H +/* Workaround to resolve conflicting declarations of termios + * in and . */ +#define termios asmtermios +#include +#undef termios +#endif +#ifdef HAVE_TERMIOS_H #include +#else +#error "termios.h must be present to control serial port" +#endif #include "gdbsupport/scoped_ignore_sigttou.h" +#if defined(HAVE_SYS_IOCTL_H) && (defined(BOTHER) || defined(IOSSIOSPEED)) +#define HAVE_CUSTOM_BAUDRATE_SUPPORT 1 +#endif + struct hardwire_ttystate { struct termios termios; @@ -289,10 +310,28 @@ baudtab[] = 4800, B4800 } , +#ifdef B7200 + { + 7200, B7200 + } + , +#endif { 9600, B9600 } , +#ifdef B14400 + { + 14400, B14400 + } + , +#endif +#ifdef B28800 + { + 28800, B28800 + } + , +#endif { 19200, B19200 } @@ -307,6 +346,12 @@ baudtab[] = } , #endif +#ifdef B76800 + { + 76800, B76800 + } + , +#endif #ifdef B115200 { 115200, B115200 @@ -412,6 +457,7 @@ rate_to_code (int rate) /* check if it is in between valid values. */ if (rate < baudtab[i].rate) { +#if !HAVE_CUSTOM_BAUDRATE_SUPPORT if (i) { error (_("Invalid baud rate %d. " @@ -423,21 +469,29 @@ rate_to_code (int rate) error (_("Invalid baud rate %d. Minimum value is %d."), rate, baudtab[0].rate); } +#else + return -1; +#endif } } } - + +#if !HAVE_CUSTOM_BAUDRATE_SUPPORT /* The requested speed was too large. */ error (_("Invalid baud rate %d. Maximum value is %d."), rate, baudtab[i - 1].rate); +#else + return -1; +#endif } +/* Set baud rate using B_code from termios.h. */ + static void -hardwire_setbaudrate (struct serial *scb, int rate) +set_baudcode_baudrate (struct serial *scb, int baud_code) { struct hardwire_ttystate state; - int baud_code = rate_to_code (rate); - + if (get_tty_state (scb, &state)) perror_with_name ("could not get tty state"); @@ -448,6 +502,101 @@ hardwire_setbaudrate (struct serial *scb, int rate) perror_with_name ("could not set tty state"); } +#if HAVE_CUSTOM_BAUDRATE_SUPPORT && defined(BOTHER) + +/* Set a custom baud rate using the termios BOTHER. */ + +static void +set_custom_baudrate_linux (int fd, int rate) +{ +#ifdef TCGETS2 + struct termios2 tio; + const unsigned long req_get = TCGETS2; + const unsigned long req_set = TCSETS2; +#else + struct termios tio; + const unsigned long req_get = TCGETS; + const unsigned long req_set = TCSETS; +#endif + + if (ioctl (fd, req_get, &tio) < 0) + { + perror_with_name ("Can not get current baud rate"); + } + + /* Clear the current output baud rate and fill a new value */ + tio.c_cflag &= ~CBAUD; + tio.c_cflag |= BOTHER; + tio.c_ospeed = rate; + + /* Clear the current input baud rate and fill a new value */ + tio.c_cflag &= ~(CBAUD << IBSHIFT); + tio.c_cflag |= BOTHER << IBSHIFT; + tio.c_ispeed = rate; + + if (ioctl (fd, req_set, &tio) < 0) + { + perror_with_name ("Can not set custom baud rate"); + } +} + +#elif HAVE_CUSTOM_BAUDRATE_SUPPORT && defined(IOSSIOSPEED) + +/* Set a custom baud rate using the IOSSIOSPEED ioctl call. */ + +static void +set_custom_baudrate_darwin (int fd, int rate) +{ + + if (ioctl (fd, IOSSIOSPEED, &rate) < 0) + { + error ("Can not set custom baud rate"); + } +} + +#endif /* HAVE_CUSTOM_BAUDRATE_SUPPORT + && (defined(BOTHER) || defined(IOSSIOSPEED)) */ + +#if HAVE_CUSTOM_BAUDRATE_SUPPORT + +/* Set a baud rate that differs from the OS B_codes. + * This is possible if one of the following macros is available: + * - BOTHER (Linux). + * - IOSSIOSPEED (Darwin). */ + +static void +set_custom_baudrate (int fd, int rate) +{ +#if defined(BOTHER) + set_custom_baudrate_linux (fd, rate); +#elif defined(IOSSIOSPEED) + set_custom_baudrate_darwin (fd, rate); +#endif +} + +#endif /* HAVE_CUSTOM_BAUDRATE_SUPPORT */ + +/* Set the baud rate for the serial communication. */ + +static void +hardwire_setbaudrate (struct serial *scb, int rate) +{ + int baud_code = rate_to_code (rate); + + if (baud_code < 0) + { +#if HAVE_CUSTOM_BAUDRATE_SUPPORT + set_custom_baudrate (scb->fd, rate); +#else + /* An error should already have been thrown by rate_to_code(). + * Add an additional error in case execution somehow reaches this line. */ + perror_with_name ("Serial baud rate was not found in B_codes"); +#endif + } + else + set_baudcode_baudrate (scb, baud_code); +} + static int hardwire_setstopbits (struct serial *scb, int num) {