[PATCHv5] gdb: unix: allow to use custom baud rate

Message ID 2a2a7715975cba13d47748424a7872012fafa2fb.camel@espressif.com
State New
Headers
Series [PATCHv5] gdb: unix: allow to use custom baud rate |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Alexey Lapshin Nov. 29, 2024, 12:38 p.m. UTC
  Modern unix systems allow to set custom baud rate instead of predefined in termios.h.

- To use this in Linux it must have BOTHER macro in "asm/termio.h"
- MacOS could handle this using IOSSIOSPEED passed to ioctl()

---
 gdb/config.in    |   6 ++
 gdb/configure    |   3 +-
 gdb/configure.ac |   3 +-
 gdb/ser-unix.c   | 158 +++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 162 insertions(+), 8 deletions(-)

-- 
2.43.0
  

Comments

Simon Marchi Nov. 29, 2024, 3:44 p.m. UTC | #1
> diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c
> index 02845aa938b..6d328c1c6f0 100644
> --- a/gdb/ser-unix.c
> +++ b/gdb/ser-unix.c
> @@ -30,9 +30,33 @@
>  #include "gdbsupport/gdb_select.h"
>  #include "cli/cli-cmds.h"
>  #include "gdbsupport/filestuff.h"
> +
> +#ifdef HAVE_SYS_IOCTL_H
> +#include <sys/ioctl.h>
> +#endif

The `include`, `define` and `undef` in these should be indented (see
what I pasted in my previous message):

#ifdef HAVE_SYS_IOCTL_H
#  include <sys/ioctl.h>
#endif

But I can fix that when I push the patch on your behalf, once your FSF
copyright assignment is set up.  Please let us know when that's done.

Simon
  

Patch

diff --git a/gdb/config.in b/gdb/config.in
index 59a5da39553..3bfe0b013db 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 <asm/termios.h> header file. */
+#undef HAVE_ASM_TERMIOS_H
+
 /* Define to 1 if you have the `btowc' function. */
 #undef HAVE_BTOWC
 
@@ -244,6 +247,9 @@ 
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
+/* Define to 1 if you have the <IOKit/serial/ioss.h> 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 ec9bbd3a842..4d63892f8d3 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -29159,7 +29159,8 @@  for ac_header in nlist.h machine/reg.h \
 		  sys/file.h sys/filio.h sys/ioctl.h sys/param.h \
 		  sys/procctl.h sys/resource.h sys/ptrace.h ptrace.h \
 		  sys/reg.h sys/debugreg.h \
-		  termios.h elf_hp.h
+		  termios.h asm/termios.h IOKit/serial/ioss.h \
+		  elf_hp.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 21f5dc8dd30..7608b592717 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1300,7 +1300,8 @@  AC_CHECK_HEADERS([nlist.h machine/reg.h \
 		  sys/file.h sys/filio.h sys/ioctl.h sys/param.h \
 		  sys/procctl.h sys/resource.h sys/ptrace.h ptrace.h \
 		  sys/reg.h sys/debugreg.h \
-		  termios.h elf_hp.h])
+		  termios.h asm/termios.h IOKit/serial/ioss.h \
+		  elf_hp.h ])
 AC_CHECK_HEADERS(sys/user.h, [], [],
 [#if HAVE_SYS_PARAM_H
 # include <sys/param.h>
diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c
index 02845aa938b..6d328c1c6f0 100644
--- a/gdb/ser-unix.c
+++ b/gdb/ser-unix.c
@@ -30,9 +30,33 @@ 
 #include "gdbsupport/gdb_select.h"
 #include "cli/cli-cmds.h"
 #include "gdbsupport/filestuff.h"
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#if HAVE_IOKIT_SERIAL_IOSS_H
+#include <IOKit/serial/ioss.h>
+#endif
+
+#if HAVE_ASM_TERMIOS_H
+/* Workaround to resolve conflicting declarations of termios
+ * in <asm/termbits.h> and <termios.h>.  */
+#define termios asmtermios
+#include <asm/termbits.h>
+#undef termios
+#endif
+
+#ifdef HAVE_TERMIOS_H
 #include <termios.h>
+#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 +313,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 +349,12 @@  baudtab[] =
   }
   ,
 #endif
+#ifdef B76800
+  {
+    76800, B76800
+  }
+  ,
+#endif
 #ifdef B115200
   {
     115200, B115200
@@ -412,6 +460,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,29 +472,126 @@  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");
+    perror_with_name (_("could not get tty state"));
 
   cfsetospeed (&state.termios, baud_code);
   cfsetispeed (&state.termios, baud_code);
 
   if (set_tty_state (scb, &state))
-    perror_with_name ("could not set tty state");
+    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)
+    perror_with_name (_("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.  */
+      gdb_assert_not_reached (_("Serial baud rate was not found in B_codes"));
+#endif
+    }
+  else
+    set_baudcode_baudrate (scb, baud_code);
 }
 
 static int