PR21985: set inferior-tty doesn't work for remote or sim

Message ID 00f001d31a99$7080bd00$51823700$@beniston.com
State New, archived
Headers

Commit Message

Jon Beniston Aug. 21, 2017, 4:20 p.m. UTC
  The set inferior-tty command doesn't appear to work for remote or sim
targets. (That is, remote targets using remote-fileio to have the IO appear
on the debug host).

This is a shame as Eclipse (and potentially other front-ends) use this
command to separate the windows used for target stdio and the gdb console.
Currently, therefore Eclipse isn't supporting remote and sim targets fully.

The attached patch adds support for this command in remote-fileio.c and
remote-sim.c. Reads/writes from/to stdin/stdout are redirected to the tty.

This may not be the ideal way to implement this within GDB, but it does get
it working with Eclipse. I'm not hugely familiar with what ttys should
offer, other than redirect stdio.

Cheers,
Jon


gdb/ChangeLog
	* remote-fileio.c (sim_inferior_data):  New field "tty".
	(gdb_os_read_stdin): New function.
	(get_sim_inferior_data): Initialise tty.
	(sim_inferior_data_cleanup): Close tty if opened.
	(init_callbacks): Add read_stdin callback.
	(gdb_os_write_stdout): Write to tty if opened.
	(gdb_os_write_stderr): Write to tty if opened.
	(gdbsim_create_inferior): Open tty if requested.
	* remote-sim.c (remote_fio_data): New field "tty".
	(remote_fileio_init_fd_map): Open tty if requested.
	(remote_fileio_func_read): read from tty if opened.
	(remote_fileio_func_write): write to tty if opened.
	(remote_fileio_reset): Close tty if opened.

     {
@@ -268,6 +274,8 @@ sim_inferior_data_cleanup (struct inferior *inf, void
*data)
 	  sim_close (sim_data->gdbsim_desc, 0);
 	  sim_data->gdbsim_desc = NULL;
 	}
+      if (sim_data->tty >= 0)
+        close (sim_data->tty);  
       xfree (sim_data);
     }
 }
@@ -306,6 +314,7 @@ init_callbacks (void)
     {
       gdb_callback = default_callback;
       gdb_callback.init (&gdb_callback);
+      gdb_callback.read_stdin = gdb_os_read_stdin;
       gdb_callback.write_stdout = gdb_os_write_stdout;
       gdb_callback.flush_stdout = gdb_os_flush_stdout;
       gdb_callback.write_stderr = gdb_os_write_stderr;
@@ -332,15 +341,34 @@ end_callbacks (void)
     }
 }
 
+/* GDB version of os_read_stdin callback.  */
+
+static int
+gdb_os_read_stdin (host_callback *p, char *buf, int len)
+{
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
+  
+  if (sim_data->tty < 0) 
+    len = ui_file_read (gdb_stdtargin, buf, len);
+  else 
+    len = read (sim_data->tty, buf, len);
+  return len;
+}
+
 /* GDB version of os_write_stdout callback.  */
 
 static int
 gdb_os_write_stdout (host_callback *p, const char *buf, int len)
 {
-  int i;
-  char b[2];
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
+
+  if (sim_data->tty < 0)
+    ui_file_write (gdb_stdtarg, buf, len);
+  else 
+    len = write (sim_data->tty, buf, len);
 
-  ui_file_write (gdb_stdtarg, buf, len);
   return len;
 }
 
@@ -357,15 +385,22 @@ gdb_os_flush_stdout (host_callback *p)
 static int
 gdb_os_write_stderr (host_callback *p, const char *buf, int len)
 {
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
   int i;
   char b[2];
 
-  for (i = 0; i < len; i++)
+  if (sim_data->tty < 0)
     {
-      b[0] = buf[i];
-      b[1] = 0;
-      fputs_unfiltered (b, gdb_stdtargerr);
+      for (i = 0; i < len; i++)
+        {
+          b[0] = buf[i];
+          b[1] = 0;
+          fputs_unfiltered (b, gdb_stdtargerr);
+        }
     }
+  else
+    len = write (sim_data->tty, buf, len);    
   return len;
 }
 
@@ -609,6 +644,7 @@ gdbsim_create_inferior (struct target_ops *target, const
char *exec_file,
   int len;
   char *arg_buf;
   const char *args = allargs.c_str ();
+  const char *term;
 
   if (exec_file == 0 || exec_bfd == 0)
     warning (_("No executable file specified."));
@@ -652,6 +688,16 @@ gdbsim_create_inferior (struct target_ops *target,
const char *exec_file,
 
   insert_breakpoints ();	/* Needed to get correct instruction
 				   in cache.  */
+  
+  /* We don't do this in open as Eclispe calls set-inferior-tty after 
+     target-select, but before run.  */
+  term = get_inferior_io_terminal ();
+  if (term != NULL)
+    {
+      sim_data->tty = open (term, O_RDWR | O_NOCTTY);
+      if (sim_data->tty < 0) 
+        error (_("Unable to open %s as inferior-tty."), term);  
+    }
 
   clear_proceed_status (0);
 }
  

Comments

Simon Marchi Sept. 3, 2017, 4:27 p.m. UTC | #1
Hi Jon,

Thanks for the patch and sorry for the delay.  When I try to apply it 
locally, git complains that it is corrupted.  Most likely your email 
client wrapped some lines.  To avoid this, I suggest using the "git 
send-email" command.  I was able to apply the patch you attached to the 
bug, however (I suppose it's the same).

Some notes about formatting:

  - Please verify the usage of tabs/spaces in the indentation.  8 
consecutive spaces become a tab.  There's at least one instance, in 
remote_fileio_func_write, that should be fixed.
  - There are some trailing spaces here and there, please remove them.

I have never used the simulator nor remote fileio, so this is a good 
pretext for me to learn about it.  Would it be possible for you to 
provide some small programs that I could toy with to test the patch (and 
how to run them, if you feel really nice :)) ?

I have some small comments inline:

On 2017-08-21 18:20, Jon Beniston wrote:
> The set inferior-tty command doesn't appear to work for remote or sim
> targets. (That is, remote targets using remote-fileio to have the IO 
> appear
> on the debug host).
> 
> This is a shame as Eclipse (and potentially other front-ends) use this
> command to separate the windows used for target stdio and the gdb 
> console.
> Currently, therefore Eclipse isn't supporting remote and sim targets 
> fully.
> 
> The attached patch adds support for this command in remote-fileio.c and
> remote-sim.c. Reads/writes from/to stdin/stdout are redirected to the 
> tty.
> 
> This may not be the ideal way to implement this within GDB, but it does 
> get
> it working with Eclipse. I'm not hugely familiar with what ttys should
> offer, other than redirect stdio.

I looks right, Eclipse (or the user) should send the "set inferior-tty" 
command, but after it shouldn't have to do anything.  GDB should take 
care of it.

> diff --git a/gdb/remote-fileio.c b/gdb/remote-fileio.c
> index 252b423bfa..d36d2e7c43 100644
> --- a/gdb/remote-fileio.c
> +++ b/gdb/remote-fileio.c
> @@ -29,6 +29,7 @@
>  #include "target.h"
>  #include "filenames.h"
>  #include "filestuff.h"
> +#include "inferior.h"
> 
>  #include <fcntl.h>
>  #include "gdb_sys_time.h"
> @@ -40,6 +41,8 @@
>  static struct {
>    int *fd_map;
>    int fd_map_size;
> +  int tty;                      /* File descriptor for tty to use if 
> set
> +                                   inferior-tty called.  */
>  } remote_fio_data;
> 
>  #define FIO_FD_INVALID		-1
> @@ -52,7 +55,8 @@ static int
>  remote_fileio_init_fd_map (void)
>  {
>    int i;
> -
> +  const char *term;

You can declare the variables where they are used.

> +
>    if (!remote_fio_data.fd_map)
>      {
>        remote_fio_data.fd_map = XNEWVEC (int, 10);
> @@ -62,6 +66,15 @@ remote_fileio_init_fd_map (void)
>        remote_fio_data.fd_map[2] = FIO_FD_CONSOLE_OUT;
>        for (i = 3; i < 10; ++i)
>          remote_fio_data.fd_map[i] = FIO_FD_INVALID;
> +      term = get_inferior_io_terminal ();
> +      if (term != NULL)
> +        {
> +          remote_fio_data.tty = open (term, O_RDWR | O_NOCTTY);

This should probably use gdb_open_cloexec.

> @@ -357,15 +385,22 @@ gdb_os_flush_stdout (host_callback *p)
>  static int
>  gdb_os_write_stderr (host_callback *p, const char *buf, int len)
>  {
> +  struct sim_inferior_data *sim_data
> +    = get_sim_inferior_data (current_inferior (), 
> SIM_INSTANCE_NEEDED);
>    int i;
>    char b[2];
> 
> -  for (i = 0; i < len; i++)
> +  if (sim_data->tty < 0)
>      {
> -      b[0] = buf[i];
> -      b[1] = 0;
> -      fputs_unfiltered (b, gdb_stdtargerr);
> +      for (i = 0; i < len; i++)
> +        {
> +          b[0] = buf[i];
> +          b[1] = 0;
> +          fputs_unfiltered (b, gdb_stdtargerr);
> +        }

The code in gdb_os_write_stdout has been changed long ago to use 
ui_file_write (and as you found, some unused variables were left) 
instead of this kind of loop.  Did you try to replace this loop here 
with a similar ui_file_write call?

>      }
> +  else
> +    len = write (sim_data->tty, buf, len);
>    return len;
>  }
> 
> @@ -609,6 +644,7 @@ gdbsim_create_inferior (struct target_ops *target, 
> const
> char *exec_file,
>    int len;
>    char *arg_buf;
>    const char *args = allargs.c_str ();
> +  const char *term;
> 
>    if (exec_file == 0 || exec_bfd == 0)
>      warning (_("No executable file specified."));
> @@ -652,6 +688,16 @@ gdbsim_create_inferior (struct target_ops *target,
> const char *exec_file,
> 
>    insert_breakpoints ();	/* Needed to get correct instruction
>  				   in cache.  */
> +
> +  /* We don't do this in open as Eclispe calls set-inferior-tty after
> +     target-select, but before run.  */

Eclispe -> Eclipse.  Although I wouldn't refer to a particular 
front-end.  You could say something more generic like:

"We do this here and not in open, so that it's possible to call "set 
inferior-tty" after connecting to the target but before run."

> +  term = get_inferior_io_terminal ();
> +  if (term != NULL)
> +    {
> +      sim_data->tty = open (term, O_RDWR | O_NOCTTY);

This should also probably use gdb_open_cloexec.

> +      if (sim_data->tty < 0)
> +        error (_("Unable to open %s as inferior-tty."), term);
> +    }
> 
>    clear_proceed_status (0);
>  }

Thanks,

Simon
  
Jon Beniston Sept. 25, 2017, 3:42 p.m. UTC | #2
Hi Simon,

>I have never used the simulator nor remote fileio, so this is a good
pretext
> for me to learn about it.  Would it be possible for you to provide some 
>small programs that I could toy with to test the patch (and how to run
them,
> if you feel really nice :)) ?

For the remote target, you'd need some h/w to connect to. For the simulator
target, you could try the lm32 target, as I know the sim supports it:

lm32-elf-gcc hello.c -g -o test.exe
lm32-elf-gdb test.exe
tar sim
load
run
"Hello World"

For a remote target, it would be something like:

lm32-elf-gdb test.exe
tar rem :1024
load
c
"Hello World"

I'll follow up with an updated patch that addresses your comments.

Thanks,
Jon
  

Patch

diff --git a/gdb/remote-fileio.c b/gdb/remote-fileio.c
index 252b423bfa..d36d2e7c43 100644
--- a/gdb/remote-fileio.c
+++ b/gdb/remote-fileio.c
@@ -29,6 +29,7 @@ 
 #include "target.h"
 #include "filenames.h"
 #include "filestuff.h"
+#include "inferior.h"
 
 #include <fcntl.h>
 #include "gdb_sys_time.h"
@@ -40,6 +41,8 @@ 
 static struct {
   int *fd_map;
   int fd_map_size;
+  int tty;                      /* File descriptor for tty to use if set 
+                                   inferior-tty called.  */
 } remote_fio_data;
 
 #define FIO_FD_INVALID		-1
@@ -52,7 +55,8 @@  static int
 remote_fileio_init_fd_map (void)
 {
   int i;
-
+  const char *term;
+  
   if (!remote_fio_data.fd_map)
     {
       remote_fio_data.fd_map = XNEWVEC (int, 10);
@@ -62,6 +66,15 @@  remote_fileio_init_fd_map (void)
       remote_fio_data.fd_map[2] = FIO_FD_CONSOLE_OUT;
       for (i = 3; i < 10; ++i)
         remote_fio_data.fd_map[i] = FIO_FD_INVALID;
+      term = get_inferior_io_terminal ();
+      if (term != NULL) 
+        {
+          remote_fio_data.tty = open (term, O_RDWR | O_NOCTTY);
+          if (remote_fio_data.tty < 0) 
+            error (_("Unable to open %s as inferior-tty."), term);
+        }
+      else  
+        remote_fio_data.tty = -1;  
     }
   return 3;
 }
@@ -505,52 +518,58 @@  remote_fileio_func_read (char *buf)
 	remote_fileio_badfd ();
 	return;
       case FIO_FD_CONSOLE_IN:
-	{
-	  static char *remaining_buf = NULL;
-	  static int remaining_length = 0;
-
-	  buffer = (gdb_byte *) xmalloc (16384);
-	  if (remaining_buf)
-	    {
-	      if (remaining_length > length)
-		{
-		  memcpy (buffer, remaining_buf, length);
-		  memmove (remaining_buf, remaining_buf + length,
-			   remaining_length - length);
-		  remaining_length -= length;
-		  ret = length;
-		}
-	      else
-		{
-		  memcpy (buffer, remaining_buf, remaining_length);
-		  xfree (remaining_buf);
-		  remaining_buf = NULL;
-		  ret = remaining_length;
-		}
-	    }
-	  else
-	    {
-	      /* Windows (at least XP and Server 2003) has difficulty
-		 with large reads from consoles.  If a handle is
-		 backed by a real console device, overly large reads
-		 from the handle will fail and set errno == ENOMEM.
-		 On a Windows Server 2003 system where I tested,
-		 reading 26608 bytes from the console was OK, but
-		 anything above 26609 bytes would fail.  The limit has
-		 been observed to vary on different systems.  So, we
-		 limit this read to something smaller than that - by a
-		 safe margin, in case the limit depends on system
-		 resources or version.  */
-	      ret = ui_file_read (gdb_stdtargin, (char *) buffer, 16383);
-	      if (ret > 0 && (size_t)ret > length)
-		{
-		  remaining_buf = (char *) xmalloc (ret - length);
-		  remaining_length = ret - length;
-		  memcpy (remaining_buf, buffer + length, remaining_length);
-		  ret = length;
-		}
-	    }
-	}
+        if (remote_fio_data.tty >= 0)
+          { 
+            buffer = (gdb_byte *) xmalloc (length);
+            ret = read (remote_fio_data.tty, buffer, length);
+          }  
+        else
+	  {
+	    static char *remaining_buf = NULL;
+	    static int remaining_length = 0;
+
+	    buffer = (gdb_byte *) xmalloc (16384);
+	    if (remaining_buf)
+	      {
+	        if (remaining_length > length)
+		  {
+		    memcpy (buffer, remaining_buf, length);
+		    memmove (remaining_buf, remaining_buf + length,
+			     remaining_length - length);
+		    remaining_length -= length;
+		    ret = length;
+		  }
+	        else
+		  {
+		    memcpy (buffer, remaining_buf, remaining_length);
+		    xfree (remaining_buf);
+		    remaining_buf = NULL;
+		    ret = remaining_length;
+		  }
+	      }
+	    else
+	      {
+	        /* Windows (at least XP and Server 2003) has difficulty
+		   with large reads from consoles.  If a handle is
+		   backed by a real console device, overly large reads
+		   from the handle will fail and set errno == ENOMEM.
+		   On a Windows Server 2003 system where I tested,
+		   reading 26608 bytes from the console was OK, but
+		   anything above 26609 bytes would fail.  The limit has
+		   been observed to vary on different systems.  So, we
+		   limit this read to something smaller than that - by a
+		   safe margin, in case the limit depends on system
+		   resources or version.  */
+	        ret = ui_file_read (gdb_stdtargin, (char *) buffer, 16383);
+	        if (ret > 0 && (size_t)ret > length)
+		  {
+		    remaining_buf = (char *) xmalloc (ret - length);
+		    remaining_length = ret - length;
+		    memcpy (remaining_buf, buffer + length,
remaining_length);
+		    ret = length;
+		  }
+	      }
+	  }
 	break;
       default:
 	buffer = (gdb_byte *) xmalloc (length);
@@ -639,10 +658,15 @@  remote_fileio_func_write (char *buf)
 	xfree (buffer);
 	return;
       case FIO_FD_CONSOLE_OUT:
-	ui_file_write (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr,
-		       (char *) buffer, length);
-	gdb_flush (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr);
-	ret = length;
+        if (remote_fio_data.tty < 0)
+          { 
+	    ui_file_write (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr,
+		           (char *) buffer, length);
+	    gdb_flush (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr);

+	    ret = length;
+          } 
+        else
+          ret = write (remote_fio_data.tty, buffer, length);
 	break;
       default:
 	ret = write (fd, buffer, length);
@@ -1160,6 +1184,8 @@  remote_fileio_reset (void)
       xfree (remote_fio_data.fd_map);
       remote_fio_data.fd_map = NULL;
       remote_fio_data.fd_map_size = 0;
+      if (remote_fio_data.tty >= 0)
+        close (remote_fio_data.tty);
     }
 }
 
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index ca824d7985..f9557111c4 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -50,6 +50,8 @@  static void init_callbacks (void);
 
 static void end_callbacks (void);
 
+static int gdb_os_read_stdin (host_callback *, char *, int);
+
 static int gdb_os_write_stdout (host_callback *, const char *, int);
 
 static void gdb_os_flush_stdout (host_callback *);
@@ -123,6 +125,9 @@  struct sim_inferior_data {
 
   /* Flag which indicates whether resume should step or not.  */
   int resume_step;
+  
+  /* File descriptor for tty to use if set inferior-tty called.  */
+  int tty;
 };
 
 /* Flag indicating the "open" status of this module.  It's set to 1
@@ -221,6 +226,7 @@  get_sim_inferior_data (struct inferior *inf, int
sim_instance_needed)
       sim_data->gdbsim_desc = sim_desc;
       sim_data->resume_siggnal = GDB_SIGNAL_0;
       sim_data->resume_step = 0;
+      sim_data->tty = -1;
     }
   else if (sim_desc)